summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStephen Rothwell <sfr@canb.auug.org.au>2009-01-19 16:37:17 +1100
committerStephen Rothwell <sfr@canb.auug.org.au>2009-01-19 16:37:17 +1100
commitefc28b23e9cc369cdd6c9d0430436856b0fb3521 (patch)
tree22cd519d1ec7c67e94213c24373b76d9ce4ad4b6
parent69cf472b8a0cb7bd0b629a6191b2dab2ca60ecaf (diff)
parent1454baaa278e49555f21f80263a12185dbd4ade2 (diff)
Merge branch 'quilt/staging'
-rw-r--r--drivers/staging/Kconfig6
-rw-r--r--drivers/staging/Makefile3
-rw-r--r--drivers/staging/android/binder.c6
-rw-r--r--drivers/staging/android/lowmemorykiller.txt16
-rw-r--r--drivers/staging/android/timed_gpio.c2
-rw-r--r--drivers/staging/comedi/Kconfig1
-rw-r--r--drivers/staging/dst/Kconfig67
-rw-r--r--drivers/staging/dst/Makefile3
-rw-r--r--drivers/staging/dst/crypto.c731
-rw-r--r--drivers/staging/dst/dcore.c972
-rw-r--r--drivers/staging/dst/export.c664
-rw-r--r--drivers/staging/dst/state.c839
-rw-r--r--drivers/staging/dst/thread_pool.c345
-rw-r--r--drivers/staging/dst/trans.c335
-rw-r--r--drivers/staging/meilhaus/Kconfig21
-rw-r--r--drivers/staging/stlc45xx/Kconfig8
-rw-r--r--drivers/staging/stlc45xx/Makefile1
-rw-r--r--drivers/staging/stlc45xx/stlc45xx.c2606
-rw-r--r--drivers/staging/stlc45xx/stlc45xx.h283
-rw-r--r--drivers/staging/stlc45xx/stlc45xx_lmac.h434
-rw-r--r--drivers/staging/sxg/sxg.c1682
-rw-r--r--drivers/staging/sxg/sxg.h884
-rw-r--r--drivers/staging/sxg/sxg_os.h100
-rw-r--r--drivers/staging/sxg/sxgdbg.h101
-rw-r--r--drivers/staging/sxg/sxghif.h1079
-rw-r--r--drivers/staging/sxg/sxghw.h1550
-rw-r--r--drivers/staging/sxg/sxgphycode.h14
-rw-r--r--drivers/staging/tuxguardian/Kconfig8
-rw-r--r--drivers/staging/tuxguardian/Makefile3
-rw-r--r--drivers/staging/tuxguardian/capability.c102
-rw-r--r--drivers/staging/tuxguardian/commoncap.c346
-rw-r--r--drivers/staging/tuxguardian/errors.h135
-rw-r--r--drivers/staging/tuxguardian/tg-defs.c406
-rw-r--r--drivers/staging/tuxguardian/tg-defs.h52
-rw-r--r--drivers/staging/tuxguardian/tg.c459
-rw-r--r--drivers/staging/tuxguardian/tg.h110
-rw-r--r--include/linux/connector.h4
-rw-r--r--include/linux/dst.h587
38 files changed, 12573 insertions, 2392 deletions
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index ce6badded47a..e4f0278ff569 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -95,5 +95,11 @@ source "drivers/staging/epl/Kconfig"
source "drivers/staging/android/Kconfig"
+source "drivers/staging/dst/Kconfig"
+
+source "drivers/staging/tuxguardian/Kconfig"
+
+source "drivers/staging/stlc45xx/Kconfig"
+
endif # !STAGING_EXCLUDE_BUILD
endif # STAGING
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index 9ddcc2bb3365..182b143f0b77 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -30,3 +30,6 @@ obj-$(CONFIG_INPUT_MIMIO) += mimio/
obj-$(CONFIG_TRANZPORT) += frontier/
obj-$(CONFIG_EPL) += epl/
obj-$(CONFIG_ANDROID) += android/
+obj-$(CONFIG_DST) += dst/
+obj-$(CONFIG_SECURITY_TUXGUARDIAN) += tuxguardian/
+obj-$(CONFIG_STLC45XX) += stlc45xx/
diff --git a/drivers/staging/android/binder.c b/drivers/staging/android/binder.c
index 6a4ceacb33f5..ab014bc96831 100644
--- a/drivers/staging/android/binder.c
+++ b/drivers/staging/android/binder.c
@@ -2649,14 +2649,14 @@ static void binder_vma_open(struct vm_area_struct *vma)
{
struct binder_proc *proc = vma->vm_private_data;
if (binder_debug_mask & BINDER_DEBUG_OPEN_CLOSE)
- printk(KERN_INFO "binder: %d open vm area %lx-%lx (%ld K) vma %lx pagep %lx\n", proc->pid, vma->vm_start, vma->vm_end, (vma->vm_end - vma->vm_start) / SZ_1K, vma->vm_flags, vma->vm_page_prot.pgprot);
+ printk(KERN_INFO "binder: %d open vm area %lx-%lx (%ld K) vma %lx pagep %lx\n", proc->pid, vma->vm_start, vma->vm_end, (vma->vm_end - vma->vm_start) / SZ_1K, vma->vm_flags, pgprot_val(vma->vm_page_prot));
dump_stack();
}
static void binder_vma_close(struct vm_area_struct *vma)
{
struct binder_proc *proc = vma->vm_private_data;
if (binder_debug_mask & BINDER_DEBUG_OPEN_CLOSE)
- printk(KERN_INFO "binder: %d close vm area %lx-%lx (%ld K) vma %lx pagep %lx\n", proc->pid, vma->vm_start, vma->vm_end, (vma->vm_end - vma->vm_start) / SZ_1K, vma->vm_flags, vma->vm_page_prot.pgprot);
+ printk(KERN_INFO "binder: %d close vm area %lx-%lx (%ld K) vma %lx pagep %lx\n", proc->pid, vma->vm_start, vma->vm_end, (vma->vm_end - vma->vm_start) / SZ_1K, vma->vm_flags, pgprot_val(vma->vm_page_prot));
proc->vma = NULL;
}
@@ -2677,7 +2677,7 @@ static int binder_mmap(struct file *filp, struct vm_area_struct *vma)
vma->vm_end = vma->vm_start + SZ_4M;
if (binder_debug_mask & BINDER_DEBUG_OPEN_CLOSE)
- printk(KERN_INFO "binder_mmap: %d %lx-%lx (%ld K) vma %lx pagep %lx\n", proc->pid, vma->vm_start, vma->vm_end, (vma->vm_end - vma->vm_start) / SZ_1K, vma->vm_flags, vma->vm_page_prot.pgprot);
+ printk(KERN_INFO "binder_mmap: %d %lx-%lx (%ld K) vma %lx pagep %lx\n", proc->pid, vma->vm_start, vma->vm_end, (vma->vm_end - vma->vm_start) / SZ_1K, vma->vm_flags, pgprot_val(vma->vm_page_prot));
if (vma->vm_flags & FORBIDDEN_MMAP_FLAGS) {
ret = -EPERM;
diff --git a/drivers/staging/android/lowmemorykiller.txt b/drivers/staging/android/lowmemorykiller.txt
new file mode 100644
index 000000000000..bd5c0c028968
--- /dev/null
+++ b/drivers/staging/android/lowmemorykiller.txt
@@ -0,0 +1,16 @@
+The lowmemorykiller driver lets user-space specify a set of memory thresholds
+where processes with a range of oom_adj values will get killed. Specify the
+minimum oom_adj values in /sys/module/lowmemorykiller/parameters/adj and the
+number of free pages in /sys/module/lowmemorykiller/parameters/minfree. Both
+files take a comma separated list of numbers in ascending order.
+
+For example, write "0,8" to /sys/module/lowmemorykiller/parameters/adj and
+"1024,4096" to /sys/module/lowmemorykiller/parameters/minfree to kill processes
+with a oom_adj value of 8 or higher when the free memory drops below 4096 pages
+and kill processes with a oom_adj value of 0 or higher when the free memory
+drops below 1024 pages.
+
+The driver considers memory used for caches to be free, but if a large
+percentage of the cached memory is locked this can be very inaccurate
+and processes may not get killed until the normal oom killer is triggered.
+
diff --git a/drivers/staging/android/timed_gpio.c b/drivers/staging/android/timed_gpio.c
index bea68c9fc942..b41b20e34628 100644
--- a/drivers/staging/android/timed_gpio.c
+++ b/drivers/staging/android/timed_gpio.c
@@ -18,7 +18,7 @@
#include <linux/platform_device.h>
#include <linux/hrtimer.h>
#include <linux/err.h>
-#include <asm/arch/gpio.h>
+#include <linux/gpio.h>
#include "timed_gpio.h"
diff --git a/drivers/staging/comedi/Kconfig b/drivers/staging/comedi/Kconfig
index b501bfb9c754..b47ca1e7e383 100644
--- a/drivers/staging/comedi/Kconfig
+++ b/drivers/staging/comedi/Kconfig
@@ -1,6 +1,7 @@
config COMEDI
tristate "Data Acquision support (comedi)"
default N
+ depends on m
---help---
Enable support a wide range of data acquision devices
for Linux.
diff --git a/drivers/staging/dst/Kconfig b/drivers/staging/dst/Kconfig
new file mode 100644
index 000000000000..74f32e7400a7
--- /dev/null
+++ b/drivers/staging/dst/Kconfig
@@ -0,0 +1,67 @@
+config DST
+ tristate "Distributed storage"
+ depends on NET && CRYPTO && SYSFS
+ select CONNECTOR
+ ---help---
+ DST is a network block device storage, which can be used to organize
+ exported storages on the remote nodes into the local block device.
+
+ DST works on top of any network media and protocol, it is just a matter
+ of configuration utility to understand the correct addresses. The most
+ common example is TCP over IP allows to pass through firewalls and
+ created remote backup storage in the different datacenter. DST requires
+ single port to be enabled on the exporting node and outgoing connections
+ on the local node.
+
+ DST works with in-kernel client and server, which improves the performance
+ eliminating unneded data copies and allows not to depend on the version
+ of the external IO components. It requires userspace configuration utility
+ though.
+
+ DST uses transaction model, when each store has to be explicitly acked
+ from the remote node to be considered as successfully written. There
+ may be lots of in-flight transactions. When remote host does not ack
+ the transaction it will be resent predefined number of times with specified
+ timeouts between them. All those parameters are configurable. Transactions
+ are marked as failed after all resends completed unsuccessfully, having
+ long enough resend timeout and/or large number of resends allows not to
+ return error to the higher (FS usually) layer in case of short network
+ problems or remote node outages. In case of network RAID setup this means
+ that storage will not degrade until transactions are marked as failed, and
+ thus will not force checksum recalculation and data rebuild. In case of
+ connection failure DST will try to reconnect to the remote node automatically.
+ DST sends ping commands at idle time to detect if remote node is alive.
+
+ Because of transactional model it is possible to use zero-copy sending
+ without worry of data corruption (which in turn could be detected by the
+ strong checksums though).
+
+ DST may fully encrypt the data channel in case of untrusted channel and implement
+ strong checksum of the transferred data. It is possible to configure algorithms
+ and crypto keys, they should match on both sides of the network channel.
+ Crypto processing does not introduce noticeble performance overhead, since DST
+ uses configurable pool of threads to perform crypto processing.
+
+ DST utilizes memory pool model of all its transaction allocations (it is the
+ only additional allocation on the client) and server allocations (bio pools,
+ while pages are allocated from the slab).
+
+ At startup DST performs a simple negotiation with the export node to determine
+ access permissions and size of the exported storage. It can be extended if
+ new parameters should be autonegotiated.
+
+ DST carries block IO flags in the protocol, which allows to transparently implement
+ barriers and sync/flush operations. Those flags are used in the export node where
+ IO against the local storage is performed, which means that sync write will be sync
+ on the remote node too, which in turn improves data integrity and improved resistance
+ to errors and data corruption during power outages or storage damages.
+
+ Homepage: http://www.ioremap.net/projects/dst
+ Userspace configuration utility and the latest releases: http://www.ioremap.net/archive/dst/
+
+config DST_DEBUG
+ bool "DST debug"
+ depends on DST
+ ---help---
+ This option will turn HEAVY debugging of the DST.
+ Turn it on ONLY if you have to debug some really obscure problem.
diff --git a/drivers/staging/dst/Makefile b/drivers/staging/dst/Makefile
new file mode 100644
index 000000000000..3a8b0cf9643e
--- /dev/null
+++ b/drivers/staging/dst/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_DST) += nst.o
+
+nst-y := dcore.o state.o export.o thread_pool.o crypto.o trans.o
diff --git a/drivers/staging/dst/crypto.c b/drivers/staging/dst/crypto.c
new file mode 100644
index 000000000000..7250f90f5924
--- /dev/null
+++ b/drivers/staging/dst/crypto.c
@@ -0,0 +1,731 @@
+/*
+ * 2007+ Copyright (c) Evgeniy Polyakov <zbr@ioremap.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.
+ */
+
+#include <linux/bio.h>
+#include <linux/crypto.h>
+#include <linux/dst.h>
+#include <linux/kernel.h>
+#include <linux/scatterlist.h>
+#include <linux/slab.h>
+
+/*
+ * Tricky bastard, but IV can be more complex with time...
+ */
+static inline u64 dst_gen_iv(struct dst_trans *t)
+{
+ return t->gen;
+}
+
+/*
+ * Crypto machinery: hash/cipher support for the given crypto controls.
+ */
+static struct crypto_hash *dst_init_hash(struct dst_crypto_ctl *ctl, u8 *key)
+{
+ int err;
+ struct crypto_hash *hash;
+
+ hash = crypto_alloc_hash(ctl->hash_algo, 0, CRYPTO_ALG_ASYNC);
+ if (IS_ERR(hash)) {
+ err = PTR_ERR(hash);
+ dprintk("%s: failed to allocate hash '%s', err: %d.\n",
+ __func__, ctl->hash_algo, err);
+ goto err_out_exit;
+ }
+
+ ctl->crypto_attached_size = crypto_hash_digestsize(hash);
+
+ if (!ctl->hash_keysize)
+ return hash;
+
+ err = crypto_hash_setkey(hash, key, ctl->hash_keysize);
+ if (err) {
+ dprintk("%s: failed to set key for hash '%s', err: %d.\n",
+ __func__, ctl->hash_algo, err);
+ goto err_out_free;
+ }
+
+ return hash;
+
+err_out_free:
+ crypto_free_hash(hash);
+err_out_exit:
+ return ERR_PTR(err);
+}
+
+static struct crypto_ablkcipher *dst_init_cipher(struct dst_crypto_ctl *ctl, u8 *key)
+{
+ int err = -EINVAL;
+ struct crypto_ablkcipher *cipher;
+
+ if (!ctl->cipher_keysize)
+ goto err_out_exit;
+
+ cipher = crypto_alloc_ablkcipher(ctl->cipher_algo, 0, 0);
+ if (IS_ERR(cipher)) {
+ err = PTR_ERR(cipher);
+ dprintk("%s: failed to allocate cipher '%s', err: %d.\n",
+ __func__, ctl->cipher_algo, err);
+ goto err_out_exit;
+ }
+
+ crypto_ablkcipher_clear_flags(cipher, ~0);
+
+ err = crypto_ablkcipher_setkey(cipher, key, ctl->cipher_keysize);
+ if (err) {
+ dprintk("%s: failed to set key for cipher '%s', err: %d.\n",
+ __func__, ctl->cipher_algo, err);
+ goto err_out_free;
+ }
+
+ return cipher;
+
+err_out_free:
+ crypto_free_ablkcipher(cipher);
+err_out_exit:
+ return ERR_PTR(err);
+}
+
+/*
+ * Crypto engine has a pool of pages to encrypt data into before sending
+ * it over the network. This pool is freed/allocated here.
+ */
+static void dst_crypto_pages_free(struct dst_crypto_engine *e)
+{
+ unsigned int i;
+
+ for (i=0; i<e->page_num; ++i)
+ __free_page(e->pages[i]);
+ kfree(e->pages);
+}
+
+static int dst_crypto_pages_alloc(struct dst_crypto_engine *e, int num)
+{
+ int i;
+
+ e->pages = kmalloc(num * sizeof(struct page **), GFP_KERNEL);
+ if (!e->pages)
+ return -ENOMEM;
+
+ for (i=0; i<num; ++i) {
+ e->pages[i] = alloc_page(GFP_KERNEL);
+ if (!e->pages[i])
+ goto err_out_free_pages;
+ }
+
+ e->page_num = num;
+ return 0;
+
+err_out_free_pages:
+ while (--i >= 0)
+ __free_page(e->pages[i]);
+
+ kfree(e->pages);
+ return -ENOMEM;
+}
+
+/*
+ * Initialize crypto engine for given node.
+ * Setup cipher/hash, keys, pool of threads and private data.
+ */
+static int dst_crypto_engine_init(struct dst_crypto_engine *e, struct dst_node *n)
+{
+ int err;
+ struct dst_crypto_ctl *ctl = &n->crypto;
+
+ err = dst_crypto_pages_alloc(e, n->max_pages);
+ if (err)
+ goto err_out_exit;
+
+ e->size = PAGE_SIZE;
+ e->data = kmalloc(e->size, GFP_KERNEL);
+ if (!e->data) {
+ err = -ENOMEM;
+ goto err_out_free_pages;
+ }
+
+ if (ctl->hash_algo[0]) {
+ e->hash = dst_init_hash(ctl, n->hash_key);
+ if (IS_ERR(e->hash)) {
+ err = PTR_ERR(e->hash);
+ e->hash = NULL;
+ goto err_out_free;
+ }
+ }
+
+ if (ctl->cipher_algo[0]) {
+ e->cipher = dst_init_cipher(ctl, n->cipher_key);
+ if (IS_ERR(e->cipher)) {
+ err = PTR_ERR(e->cipher);
+ e->cipher = NULL;
+ goto err_out_free_hash;
+ }
+ }
+
+ return 0;
+
+err_out_free_hash:
+ crypto_free_hash(e->hash);
+err_out_free:
+ kfree(e->data);
+err_out_free_pages:
+ dst_crypto_pages_free(e);
+err_out_exit:
+ return err;
+}
+
+static void dst_crypto_engine_exit(struct dst_crypto_engine *e)
+{
+ if (e->hash)
+ crypto_free_hash(e->hash);
+ if (e->cipher)
+ crypto_free_ablkcipher(e->cipher);
+ dst_crypto_pages_free(e);
+ kfree(e->data);
+}
+
+/*
+ * Waiting for cipher processing to be completed.
+ */
+struct dst_crypto_completion
+{
+ struct completion complete;
+ int error;
+};
+
+static void dst_crypto_complete(struct crypto_async_request *req, int err)
+{
+ struct dst_crypto_completion *c = req->data;
+
+ if (err == -EINPROGRESS)
+ return;
+
+ dprintk("%s: req: %p, err: %d.\n", __func__, req, err);
+ c->error = err;
+ complete(&c->complete);
+}
+
+static int dst_crypto_process(struct ablkcipher_request *req,
+ struct scatterlist *sg_dst, struct scatterlist *sg_src,
+ void *iv, int enc, unsigned long timeout)
+{
+ struct dst_crypto_completion c;
+ int err;
+
+ init_completion(&c.complete);
+ c.error = -EINPROGRESS;
+
+ ablkcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
+ dst_crypto_complete, &c);
+
+ ablkcipher_request_set_crypt(req, sg_src, sg_dst, sg_src->length, iv);
+
+ if (enc)
+ err = crypto_ablkcipher_encrypt(req);
+ else
+ err = crypto_ablkcipher_decrypt(req);
+
+ switch (err) {
+ case -EINPROGRESS:
+ case -EBUSY:
+ err = wait_for_completion_interruptible_timeout(&c.complete,
+ timeout);
+ if (!err)
+ err = -ETIMEDOUT;
+ else
+ err = c.error;
+ break;
+ default:
+ break;
+ }
+
+ return err;
+}
+
+/*
+ * DST uses generic iteration approach for data crypto processing.
+ * Single block IO request is switched into array of scatterlists,
+ * which are submitted to the crypto processing iterator.
+ *
+ * Input and output iterator initialization are different, since
+ * in output case we can not encrypt data in-place and need a
+ * temporary storage, which is then being sent to the remote peer.
+ */
+static int dst_trans_iter_out(struct bio *bio, struct dst_crypto_engine *e,
+ int (* iterator) (struct dst_crypto_engine *e,
+ struct scatterlist *dst,
+ struct scatterlist *src))
+{
+ struct bio_vec *bv;
+ int err, i;
+
+ sg_init_table(e->src, bio->bi_vcnt);
+ sg_init_table(e->dst, bio->bi_vcnt);
+
+ bio_for_each_segment(bv, bio, i) {
+ sg_set_page(&e->src[i], bv->bv_page, bv->bv_len, bv->bv_offset);
+ sg_set_page(&e->dst[i], e->pages[i], bv->bv_len, bv->bv_offset);
+
+ err = iterator(e, &e->dst[i], &e->src[i]);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+static int dst_trans_iter_in(struct bio *bio, struct dst_crypto_engine *e,
+ int (* iterator) (struct dst_crypto_engine *e,
+ struct scatterlist *dst,
+ struct scatterlist *src))
+{
+ struct bio_vec *bv;
+ int err, i;
+
+ sg_init_table(e->src, bio->bi_vcnt);
+ sg_init_table(e->dst, bio->bi_vcnt);
+
+ bio_for_each_segment(bv, bio, i) {
+ sg_set_page(&e->src[i], bv->bv_page, bv->bv_len, bv->bv_offset);
+ sg_set_page(&e->dst[i], bv->bv_page, bv->bv_len, bv->bv_offset);
+
+ err = iterator(e, &e->dst[i], &e->src[i]);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+static int dst_crypt_iterator(struct dst_crypto_engine *e,
+ struct scatterlist *sg_dst, struct scatterlist *sg_src)
+{
+ struct ablkcipher_request *req = e->data;
+ u8 iv[32];
+
+ memset(iv, 0, sizeof(iv));
+
+ memcpy(iv, &e->iv, sizeof(e->iv));
+
+ return dst_crypto_process(req, sg_dst, sg_src, iv, e->enc, e->timeout);
+}
+
+static int dst_crypt(struct dst_crypto_engine *e, struct bio *bio)
+{
+ struct ablkcipher_request *req = e->data;
+
+ memset(req, 0, sizeof(struct ablkcipher_request));
+ ablkcipher_request_set_tfm(req, e->cipher);
+
+ if (e->enc)
+ return dst_trans_iter_out(bio, e, dst_crypt_iterator);
+ else
+ return dst_trans_iter_in(bio, e, dst_crypt_iterator);
+}
+
+static int dst_hash_iterator(struct dst_crypto_engine *e,
+ struct scatterlist *sg_dst, struct scatterlist *sg_src)
+{
+ return crypto_hash_update(e->data, sg_src, sg_src->length);
+}
+
+static int dst_hash(struct dst_crypto_engine *e, struct bio *bio, void *dst)
+{
+ struct hash_desc *desc = e->data;
+ int err;
+
+ desc->tfm = e->hash;
+ desc->flags = 0;
+
+ err = crypto_hash_init(desc);
+ if (err)
+ return err;
+
+ err = dst_trans_iter_in(bio, e, dst_hash_iterator);
+ if (err)
+ return err;
+
+ err = crypto_hash_final(desc, dst);
+ if (err)
+ return err;
+
+ return 0;
+}
+
+/*
+ * Initialize/cleanup a crypto thread. The only thing it should
+ * do is to allocate a pool of pages as temporary storage.
+ * And to setup cipher and/or hash.
+ */
+static void *dst_crypto_thread_init(void *data)
+{
+ struct dst_node *n = data;
+ struct dst_crypto_engine *e;
+ int err = -ENOMEM;
+
+ e = kzalloc(sizeof(struct dst_crypto_engine), GFP_KERNEL);
+ if (!e)
+ goto err_out_exit;
+ e->src = kcalloc(2 * n->max_pages, sizeof(struct scatterlist),
+ GFP_KERNEL);
+ if (!e->src)
+ goto err_out_free;
+
+ e->dst = e->src + n->max_pages;
+
+ err = dst_crypto_engine_init(e, n);
+ if (err)
+ goto err_out_free_all;
+
+ return e;
+
+err_out_free_all:
+ kfree(e->src);
+err_out_free:
+ kfree(e);
+err_out_exit:
+ return ERR_PTR(err);
+}
+
+static void dst_crypto_thread_cleanup(void *private)
+{
+ struct dst_crypto_engine *e = private;
+
+ dst_crypto_engine_exit(e);
+ kfree(e->src);
+ kfree(e);
+}
+
+/*
+ * Initialize crypto engine for given node: store keys, create pool
+ * of threads, initialize each one.
+ *
+ * Each thread has unique ID, but 0 and 1 are reserved for receiving and accepting
+ * threads (if export node), so IDs could start from 2, but starting them
+ * from 10 allows easily understand what this thread is for.
+ */
+int dst_node_crypto_init(struct dst_node *n, struct dst_crypto_ctl *ctl)
+{
+ void *key = (ctl + 1);
+ int err = -ENOMEM, i;
+ char name[32];
+
+ if (ctl->hash_keysize) {
+ n->hash_key = kmalloc(ctl->hash_keysize, GFP_KERNEL);
+ if (!n->hash_key)
+ goto err_out_exit;
+ memcpy(n->hash_key, key, ctl->hash_keysize);
+ }
+
+ if (ctl->cipher_keysize) {
+ n->cipher_key = kmalloc(ctl->cipher_keysize, GFP_KERNEL);
+ if (!n->cipher_key)
+ goto err_out_free_hash;
+ memcpy(n->cipher_key, key, ctl->cipher_keysize);
+ }
+ memcpy(&n->crypto, ctl, sizeof(struct dst_crypto_ctl));
+
+ for (i=0; i<ctl->thread_num; ++i) {
+ snprintf(name, sizeof(name), "%s-crypto-%d", n->name, i);
+ /* Unique ids... */
+ err = thread_pool_add_worker(n->pool, name, i+10,
+ dst_crypto_thread_init, dst_crypto_thread_cleanup, n);
+ if (err)
+ goto err_out_free_threads;
+ }
+
+ return 0;
+
+err_out_free_threads:
+ while (--i >= 0)
+ thread_pool_del_worker_id(n->pool, i+10);
+
+ if (ctl->cipher_keysize)
+ kfree(n->cipher_key);
+ ctl->cipher_keysize = 0;
+err_out_free_hash:
+ if (ctl->hash_keysize)
+ kfree(n->hash_key);
+ ctl->hash_keysize = 0;
+err_out_exit:
+ return err;
+}
+
+void dst_node_crypto_exit(struct dst_node *n)
+{
+ struct dst_crypto_ctl *ctl = &n->crypto;
+
+ if (ctl->cipher_algo[0] || ctl->hash_algo[0]) {
+ kfree(n->hash_key);
+ kfree(n->cipher_key);
+ }
+}
+
+/*
+ * Thrad pool setup callback. Just stores a transaction in private data.
+ */
+static int dst_trans_crypto_setup(void *crypto_engine, void *trans)
+{
+ struct dst_crypto_engine *e = crypto_engine;
+
+ e->private = trans;
+ return 0;
+}
+
+#if 0
+static void dst_dump_bio(struct bio *bio)
+{
+ u8 *p;
+ struct bio_vec *bv;
+ int i;
+
+ bio_for_each_segment(bv, bio, i) {
+ dprintk("%s: %llu/%u: size: %u, offset: %u, data: ",
+ __func__, bio->bi_sector, bio->bi_size,
+ bv->bv_len, bv->bv_offset);
+
+ p = kmap(bv->bv_page) + bv->bv_offset;
+ for (i=0; i<bv->bv_len; ++i)
+ printk("%02x ", p[i]);
+ kunmap(bv->bv_page);
+ printk("\n");
+ }
+}
+#endif
+
+/*
+ * Encrypt/hash data and send it to the network.
+ */
+static int dst_crypto_process_sending(struct dst_crypto_engine *e,
+ struct bio *bio, u8 *hash)
+{
+ int err;
+
+ if (e->cipher) {
+ err = dst_crypt(e, bio);
+ if (err)
+ goto err_out_exit;
+ }
+
+ if (e->hash) {
+ err = dst_hash(e, bio, hash);
+ if (err)
+ goto err_out_exit;
+
+#ifdef CONFIG_DST_DEBUG
+ {
+ unsigned int i;
+
+ /* dst_dump_bio(bio); */
+
+ printk(KERN_DEBUG "%s: bio: %llu/%u, rw: %lu, hash: ",
+ __func__, (u64)bio->bi_sector,
+ bio->bi_size, bio_data_dir(bio));
+ for (i=0; i<crypto_hash_digestsize(e->hash); ++i)
+ printk("%02x ", hash[i]);
+ printk("\n");
+ }
+#endif
+ }
+
+ return 0;
+
+err_out_exit:
+ return err;
+}
+
+/*
+ * Check if received data is valid. Decipher if it is.
+ */
+static int dst_crypto_process_receiving(struct dst_crypto_engine *e,
+ struct bio *bio, u8 *hash, u8 *recv_hash)
+{
+ int err;
+
+ if (e->hash) {
+ int mismatch;
+
+ err = dst_hash(e, bio, hash);
+ if (err)
+ goto err_out_exit;
+
+ mismatch = !!memcmp(recv_hash, hash,
+ crypto_hash_digestsize(e->hash));
+#ifdef CONFIG_DST_DEBUG
+ /* dst_dump_bio(bio); */
+
+ printk(KERN_DEBUG "%s: bio: %llu/%u, rw: %lu, hash mismatch: %d",
+ __func__, (u64)bio->bi_sector, bio->bi_size,
+ bio_data_dir(bio), mismatch);
+ if (mismatch) {
+ unsigned int i;
+
+ printk(", recv/calc: ");
+ for (i=0; i<crypto_hash_digestsize(e->hash); ++i) {
+ printk("%02x/%02x ", recv_hash[i], hash[i]);
+ }
+ }
+ printk("\n");
+#endif
+ err = -1;
+ if (mismatch)
+ goto err_out_exit;
+ }
+
+ if (e->cipher) {
+ err = dst_crypt(e, bio);
+ if (err)
+ goto err_out_exit;
+ }
+
+ return 0;
+
+err_out_exit:
+ return err;
+}
+
+/*
+ * Thread pool callback to encrypt data and send it to the netowork.
+ */
+static int dst_trans_crypto_action(void *crypto_engine, void *schedule_data)
+{
+ struct dst_crypto_engine *e = crypto_engine;
+ struct dst_trans *t = schedule_data;
+ struct bio *bio = t->bio;
+ int err;
+
+ dprintk("%s: t: %p, gen: %llu, cipher: %p, hash: %p.\n",
+ __func__, t, t->gen, e->cipher, e->hash);
+
+ e->enc = t->enc;
+ e->iv = dst_gen_iv(t);
+
+ if (bio_data_dir(bio) == WRITE) {
+ err = dst_crypto_process_sending(e, bio, t->cmd.hash);
+ if (err)
+ goto err_out_exit;
+
+ if (e->hash) {
+ t->cmd.csize = crypto_hash_digestsize(e->hash);
+ t->cmd.size += t->cmd.csize;
+ }
+
+ return dst_trans_send(t);
+ } else {
+ u8 *hash = e->data + e->size/2;
+
+ err = dst_crypto_process_receiving(e, bio, hash, t->cmd.hash);
+ if (err)
+ goto err_out_exit;
+
+ dst_trans_remove(t);
+ dst_trans_put(t);
+ }
+
+ return 0;
+
+err_out_exit:
+ t->error = err;
+ dst_trans_put(t);
+ return err;
+}
+
+/*
+ * Schedule crypto processing for given transaction.
+ */
+int dst_trans_crypto(struct dst_trans *t)
+{
+ struct dst_node *n = t->n;
+ int err;
+
+ err = thread_pool_schedule(n->pool,
+ dst_trans_crypto_setup, dst_trans_crypto_action,
+ t, MAX_SCHEDULE_TIMEOUT);
+ if (err)
+ goto err_out_exit;
+
+ return 0;
+
+err_out_exit:
+ dst_trans_put(t);
+ return err;
+}
+
+/*
+ * Crypto machinery for the export node.
+ */
+static int dst_export_crypto_setup(void *crypto_engine, void *bio)
+{
+ struct dst_crypto_engine *e = crypto_engine;
+
+ e->private = bio;
+ return 0;
+}
+
+static int dst_export_crypto_action(void *crypto_engine, void *schedule_data)
+{
+ struct dst_crypto_engine *e = crypto_engine;
+ struct bio *bio = schedule_data;
+ struct dst_export_priv *p = bio->bi_private;
+ int err;
+
+ dprintk("%s: e: %p, data: %p, bio: %llu/%u, dir: %lu.\n", __func__,
+ e, e->data, (u64)bio->bi_sector, bio->bi_size, bio_data_dir(bio));
+
+ e->enc = (bio_data_dir(bio) == READ);
+ e->iv = p->cmd.id;
+
+ if (bio_data_dir(bio) == WRITE) {
+ u8 *hash = e->data + e->size/2;
+
+ err = dst_crypto_process_receiving(e, bio, hash, p->cmd.hash);
+ if (err)
+ goto err_out_exit;
+
+ generic_make_request(bio);
+ } else {
+ err = dst_crypto_process_sending(e, bio, p->cmd.hash);
+ if (err)
+ goto err_out_exit;
+
+ if (e->hash) {
+ p->cmd.csize = crypto_hash_digestsize(e->hash);
+ p->cmd.size += p->cmd.csize;
+ }
+
+ err = dst_export_send_bio(bio);
+ }
+ return 0;
+
+err_out_exit:
+ bio_put(bio);
+ return err;
+}
+
+int dst_export_crypto(struct dst_node *n, struct bio *bio)
+{
+ int err;
+
+ err = thread_pool_schedule(n->pool,
+ dst_export_crypto_setup, dst_export_crypto_action,
+ bio, MAX_SCHEDULE_TIMEOUT);
+ if (err)
+ goto err_out_exit;
+
+ return 0;
+
+err_out_exit:
+ bio_put(bio);
+ return err;
+}
diff --git a/drivers/staging/dst/dcore.c b/drivers/staging/dst/dcore.c
new file mode 100644
index 000000000000..c6e3cd1a5051
--- /dev/null
+++ b/drivers/staging/dst/dcore.c
@@ -0,0 +1,972 @@
+/*
+ * 2007+ Copyright (c) Evgeniy Polyakov <zbr@ioremap.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.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/blkdev.h>
+#include <linux/bio.h>
+#include <linux/buffer_head.h>
+#include <linux/connector.h>
+#include <linux/dst.h>
+#include <linux/device.h>
+#include <linux/jhash.h>
+#include <linux/idr.h>
+#include <linux/init.h>
+#include <linux/namei.h>
+#include <linux/slab.h>
+#include <linux/socket.h>
+
+#include <linux/in.h>
+#include <linux/in6.h>
+
+#include <net/sock.h>
+
+static int dst_major;
+
+static DEFINE_MUTEX(dst_hash_lock);
+static struct list_head *dst_hashtable;
+static unsigned int dst_hashtable_size = 128;
+module_param(dst_hashtable_size, uint, 0644);
+
+static char dst_name[] = "Dementianting goldfish";
+
+static DEFINE_IDR(dst_index_idr);
+static struct cb_id cn_dst_id = { CN_DST_IDX, CN_DST_VAL };
+
+/*
+ * DST sysfs tree for device called 'storage':
+ *
+ * /sys/bus/dst/devices/storage/
+ * /sys/bus/dst/devices/storage/type : 192.168.4.80:1025
+ * /sys/bus/dst/devices/storage/size : 800
+ * /sys/bus/dst/devices/storage/name : storage
+ */
+
+static int dst_dev_match(struct device *dev, struct device_driver *drv)
+{
+ return 1;
+}
+
+static struct bus_type dst_dev_bus_type = {
+ .name = "dst",
+ .match = &dst_dev_match,
+};
+
+static void dst_node_release(struct device *dev)
+{
+ struct dst_info *info = container_of(dev, struct dst_info, device);
+
+ kfree(info);
+}
+
+static struct device dst_node_dev = {
+ .bus = &dst_dev_bus_type,
+ .release = &dst_node_release
+};
+
+/*
+ * Setting size of the node after it was changed.
+ */
+static void dst_node_set_size(struct dst_node *n)
+{
+ struct block_device *bdev;
+
+ set_capacity(n->disk, n->size >> 9);
+
+ bdev = bdget_disk(n->disk, 0);
+ if (bdev) {
+ mutex_lock(&bdev->bd_inode->i_mutex);
+ i_size_write(bdev->bd_inode, n->size);
+ mutex_unlock(&bdev->bd_inode->i_mutex);
+ bdput(bdev);
+ }
+}
+
+/*
+ * Distributed storage request processing function.
+ */
+static int dst_request(struct request_queue *q, struct bio *bio)
+{
+ struct dst_node *n = q->queuedata;
+
+ bio_get(bio);
+
+ return dst_process_bio(n, bio);
+}
+
+/*
+ * Open/close callbacks for appropriate block device.
+ */
+static int dst_bdev_open(struct block_device *bdev, fmode_t mode)
+{
+ struct dst_node *n = bdev->bd_disk->private_data;
+
+ dst_node_get(n);
+ return 0;
+}
+
+static int dst_bdev_release(struct gendisk *disk, fmode_t mode)
+{
+ struct dst_node *n = disk->private_data;
+
+ dst_node_put(n);
+ return 0;
+}
+
+static struct block_device_operations dst_blk_ops = {
+ .open = dst_bdev_open,
+ .release = dst_bdev_release,
+ .owner = THIS_MODULE,
+};
+
+/*
+ * Block layer binding - disk is created when array is fully configured
+ * by userspace request.
+ */
+static int dst_node_create_disk(struct dst_node *n)
+{
+ int err = -ENOMEM;
+ u32 index = 0;
+
+ n->queue = blk_init_queue(NULL, NULL);
+ if (!n->queue)
+ goto err_out_exit;
+
+ n->queue->queuedata = n;
+ blk_queue_make_request(n->queue, dst_request);
+ blk_queue_max_phys_segments(n->queue, n->max_pages);
+ blk_queue_max_hw_segments(n->queue, n->max_pages);
+
+ err = -ENOMEM;
+ n->disk = alloc_disk(1);
+ if (!n->disk)
+ goto err_out_free_queue;
+
+ if (!(n->state->permissions & DST_PERM_WRITE)) {
+ printk(KERN_INFO "DST node %s attached read-only.\n", n->name);
+ set_disk_ro(n->disk, 1);
+ }
+
+ if (!idr_pre_get(&dst_index_idr, GFP_KERNEL))
+ goto err_out_put;
+
+ mutex_lock(&dst_hash_lock);
+ err = idr_get_new(&dst_index_idr, NULL, &index);
+ mutex_unlock(&dst_hash_lock);
+ if (err)
+ goto err_out_put;
+
+ n->disk->major = dst_major;
+ n->disk->first_minor = index;
+ n->disk->fops = &dst_blk_ops;
+ n->disk->queue = n->queue;
+ n->disk->private_data = n;
+ snprintf(n->disk->disk_name, sizeof(n->disk->disk_name), "dst-%s", n->name);
+
+ return 0;
+
+err_out_put:
+ put_disk(n->disk);
+err_out_free_queue:
+ blk_cleanup_queue(n->queue);
+err_out_exit:
+ return err;
+}
+
+/*
+ * Sysfs machinery: show device's size.
+ */
+static ssize_t dst_show_size(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct dst_info *info = container_of(dev, struct dst_info, device);
+
+ return sprintf(buf, "%llu\n", info->size);
+}
+
+/*
+ * Show local exported device.
+ */
+static ssize_t dst_show_local(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct dst_info *info = container_of(dev, struct dst_info, device);
+
+ return sprintf(buf, "%s\n", info->local);
+}
+
+/*
+ * Shows type of the remote node - device major/minor number
+ * for local nodes and address (af_inet ipv4/ipv6 only) for remote nodes.
+ */
+static ssize_t dst_show_type(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct dst_info *info = container_of(dev, struct dst_info, device);
+ int family = info->net.addr.sa_family;
+
+ if (family == AF_INET) {
+ struct sockaddr_in *sin = (struct sockaddr_in *)&info->net.addr;
+ return sprintf(buf, "%u.%u.%u.%u:%d\n",
+ NIPQUAD(sin->sin_addr.s_addr), ntohs(sin->sin_port));
+ } else if (family == AF_INET6) {
+ struct sockaddr_in6 *sin = (struct sockaddr_in6 *)&info->net.addr;
+ return sprintf(buf,
+ "%pi6:%d\n",
+ &sin->sin6_addr, ntohs(sin->sin6_port));
+ } else {
+ int i, sz = PAGE_SIZE - 2; /* 0 symbol and '\n' below */
+ int size, addrlen = info->net.addr.sa_data_len;
+ unsigned char *a = (unsigned char *)&info->net.addr.sa_data;
+ char *buf_orig = buf;
+
+ size = snprintf(buf, sz, "family: %d, addrlen: %u, addr: ",
+ family, addrlen);
+ sz -= size;
+ buf += size;
+
+ for (i=0; i<addrlen; ++i) {
+ if (sz < 3)
+ break;
+
+ size = snprintf(buf, sz, "%02x ", a[i]);
+ sz -= size;
+ buf += size;
+ }
+ buf += sprintf(buf, "\n");
+
+ return buf - buf_orig;
+ }
+ return 0;
+}
+
+static struct device_attribute dst_node_attrs[] = {
+ __ATTR(size, 0444, dst_show_size, NULL),
+ __ATTR(type, 0444, dst_show_type, NULL),
+ __ATTR(local, 0444, dst_show_local, NULL),
+};
+
+static int dst_create_node_attributes(struct dst_node *n)
+{
+ int err, i;
+
+ for (i=0; i<ARRAY_SIZE(dst_node_attrs); ++i) {
+ err = device_create_file(&n->info->device,
+ &dst_node_attrs[i]);
+ if (err)
+ goto err_out_remove_all;
+ }
+ return 0;
+
+err_out_remove_all:
+ while (--i >= 0)
+ device_remove_file(&n->info->device,
+ &dst_node_attrs[i]);
+
+ return err;
+}
+
+static void dst_remove_node_attributes(struct dst_node *n)
+{
+ int i;
+
+ for (i=0; i<ARRAY_SIZE(dst_node_attrs); ++i)
+ device_remove_file(&n->info->device,
+ &dst_node_attrs[i]);
+}
+
+/*
+ * Sysfs cleanup and initialization.
+ * Shows number of useful parameters.
+ */
+static void dst_node_sysfs_exit(struct dst_node *n)
+{
+ if (n->info) {
+ dst_remove_node_attributes(n);
+ device_unregister(&n->info->device);
+ n->info = NULL;
+ }
+}
+
+static int dst_node_sysfs_init(struct dst_node *n)
+{
+ int err;
+
+ n->info = kzalloc(sizeof(struct dst_info), GFP_KERNEL);
+ if (!n->info)
+ return -ENOMEM;
+
+ memcpy(&n->info->device, &dst_node_dev, sizeof(struct device));
+ n->info->size = n->size;
+
+ snprintf(n->info->device.bus_id, sizeof(n->info->device.bus_id), "dst-%s", n->name);
+ err = device_register(&n->info->device);
+ if (err) {
+ dprintk(KERN_ERR "Failed to register node '%s', err: %d.\n",
+ n->name, err);
+ goto err_out_exit;
+ }
+
+ dst_create_node_attributes(n);
+
+ return 0;
+
+err_out_exit:
+ kfree(n->info);
+ n->info = NULL;
+ return err;
+}
+
+/*
+ * DST node hash tables machinery.
+ */
+static inline unsigned int dst_hash(char *str, unsigned int size)
+{
+ return (jhash(str, size, 0) % dst_hashtable_size);
+}
+
+static void dst_node_remove(struct dst_node *n)
+{
+ mutex_lock(&dst_hash_lock);
+ list_del_init(&n->node_entry);
+ mutex_unlock(&dst_hash_lock);
+}
+
+static void dst_node_add(struct dst_node *n)
+{
+ unsigned hash = dst_hash(n->name, sizeof(n->name));
+
+ mutex_lock(&dst_hash_lock);
+ list_add_tail(&n->node_entry, &dst_hashtable[hash]);
+ mutex_unlock(&dst_hash_lock);
+}
+
+/*
+ * Cleaning node when it is about to be freed.
+ * There are still users of the socket though,
+ * so connection cleanup should be protected.
+ */
+static void dst_node_cleanup(struct dst_node *n)
+{
+ struct dst_state *st = n->state;
+
+ if (!st)
+ return;
+
+ if (n->queue) {
+ blk_cleanup_queue(n->queue);
+
+ mutex_lock(&dst_hash_lock);
+ idr_remove(&dst_index_idr, n->disk->first_minor);
+ mutex_unlock(&dst_hash_lock);
+
+ put_disk(n->disk);
+ }
+
+ if (n->bdev) {
+ sync_blockdev(n->bdev);
+ blkdev_put(n->bdev, FMODE_READ|FMODE_WRITE);
+ }
+
+ dst_state_lock(st);
+ st->need_exit = 1;
+ dst_state_exit_connected(st);
+ dst_state_unlock(st);
+
+ wake_up(&st->thread_wait);
+
+ dst_state_put(st);
+ n->state = NULL;
+}
+
+/*
+ * Free security attributes attached to given node.
+ */
+static void dst_security_exit(struct dst_node *n)
+{
+ struct dst_secure *s, *tmp;
+
+ list_for_each_entry_safe(s, tmp, &n->security_list, sec_entry) {
+ list_del(&s->sec_entry);
+ kfree(s);
+ }
+}
+
+/*
+ * Free node when there are no more users.
+ * Actually node has to be freed on behalf od userspace process,
+ * since there are number of threads, which are embedded in the
+ * node, so they can not exit and free node from there, that is
+ * why there is a wakeup if reference counter is not equal to zero.
+ */
+void dst_node_put(struct dst_node *n)
+{
+ if (unlikely(!n))
+ return;
+
+ dprintk("%s: n: %p, refcnt: %d.\n",
+ __func__, n, atomic_read(&n->refcnt));
+
+ if (atomic_dec_and_test(&n->refcnt)) {
+ dst_node_remove(n);
+ n->trans_scan_timeout = 0;
+ dst_node_cleanup(n);
+ thread_pool_destroy(n->pool);
+ dst_node_sysfs_exit(n);
+ dst_node_crypto_exit(n);
+ dst_security_exit(n);
+ dst_node_trans_exit(n);
+
+ kfree(n);
+
+ dprintk("%s: freed n: %p.\n", __func__, n);
+ } else {
+ wake_up(&n->wait);
+ }
+}
+
+/*
+ * This function finds devices major/minor numbers for given pathname.
+ */
+static int dst_lookup_device(const char *path, dev_t *dev)
+{
+ int err;
+ struct nameidata nd;
+ struct inode *inode;
+
+ err = path_lookup(path, LOOKUP_FOLLOW, &nd);
+ if (err)
+ return err;
+
+ inode = nd.path.dentry->d_inode;
+ if (!inode) {
+ err = -ENOENT;
+ goto out;
+ }
+
+ if (!S_ISBLK(inode->i_mode)) {
+ err = -ENOTBLK;
+ goto out;
+ }
+
+ *dev = inode->i_rdev;
+
+out:
+ path_put(&nd.path);
+ return err;
+}
+
+/*
+ * Setting up export device: lookup by the name, get its size
+ * and setup listening socket, which will accept clients, which
+ * will submit IO for given storage.
+ */
+static int dst_setup_export(struct dst_node *n, struct dst_ctl *ctl,
+ struct dst_export_ctl *le)
+{
+ int err;
+ dev_t dev = 0; /* gcc likes to scream here */
+
+ snprintf(n->info->local, sizeof(n->info->local), "%s", le->device);
+
+ err = dst_lookup_device(le->device, &dev);
+ if (err)
+ return err;
+
+ n->bdev = open_by_devnum(dev, FMODE_READ|FMODE_WRITE);
+ if (!n->bdev)
+ return -ENODEV;
+
+ if (n->size != 0)
+ n->size = min_t(loff_t, n->bdev->bd_inode->i_size, n->size);
+ else
+ n->size = n->bdev->bd_inode->i_size;
+
+ n->info->size = n->size;
+ err = dst_node_init_listened(n, le);
+ if (err)
+ goto err_out_cleanup;
+
+ return 0;
+
+err_out_cleanup:
+ blkdev_put(n->bdev, FMODE_READ|FMODE_WRITE);
+ n->bdev = NULL;
+
+ return err;
+}
+
+/* Empty thread pool callbacks for the network processing threads. */
+static inline void *dst_thread_network_init(void *data)
+{
+ dprintk("%s: data: %p.\n", __func__, data);
+ return data;
+}
+
+static inline void dst_thread_network_cleanup(void *data)
+{
+ dprintk("%s: data: %p.\n", __func__, data);
+}
+
+/*
+ * Allocate DST node and initialize some of its parameters.
+ */
+static struct dst_node *dst_alloc_node(struct dst_ctl *ctl,
+ int (*start)(struct dst_node *),
+ int num)
+{
+ struct dst_node *n;
+ int err;
+
+ n = kzalloc(sizeof(struct dst_node), GFP_KERNEL);
+ if (!n)
+ return NULL;
+
+ INIT_LIST_HEAD(&n->node_entry);
+
+ INIT_LIST_HEAD(&n->security_list);
+ mutex_init(&n->security_lock);
+
+ init_waitqueue_head(&n->wait);
+
+ n->trans_scan_timeout = msecs_to_jiffies(ctl->trans_scan_timeout);
+ if (!n->trans_scan_timeout)
+ n->trans_scan_timeout = HZ;
+
+ n->trans_max_retries = ctl->trans_max_retries;
+ if (!n->trans_max_retries)
+ n->trans_max_retries = 10;
+
+ /*
+ * Pretty much arbitrary default numbers.
+ * 32 matches maximum number of pages in bio originated from ext3 (31).
+ */
+ n->max_pages = ctl->max_pages;
+ if (!n->max_pages)
+ n->max_pages = 32;
+
+ if (n->max_pages > 1024)
+ n->max_pages = 1024;
+
+ n->start = start;
+ n->size = ctl->size;
+
+ atomic_set(&n->refcnt, 1);
+ atomic_long_set(&n->gen, 0);
+ snprintf(n->name, sizeof(n->name), "%s", ctl->name);
+
+ err = dst_node_sysfs_init(n);
+ if (err)
+ goto err_out_free;
+
+ n->pool = thread_pool_create(num, n->name, dst_thread_network_init,
+ dst_thread_network_cleanup, n);
+ if (IS_ERR(n->pool)) {
+ err = PTR_ERR(n->pool);
+ goto err_out_sysfs_exit;
+ }
+
+ dprintk("%s: n: %p, name: %s.\n", __func__, n, n->name);
+
+ return n;
+
+err_out_sysfs_exit:
+ dst_node_sysfs_exit(n);
+err_out_free:
+ kfree(n);
+ return NULL;
+}
+
+/*
+ * Starting a node, connected to the remote server:
+ * register block device and initialize transaction mechanism.
+ * In revers order though.
+ *
+ * It will autonegotiate some parameters with the remote node
+ * and update local if needed.
+ *
+ * Transaction initialization should be the last thing before
+ * starting the node, since transaction should include not only
+ * block IO, but also crypto related data (if any), which are
+ * initialized separately.
+ */
+static int dst_start_remote(struct dst_node *n)
+{
+ int err;
+
+ err = dst_node_trans_init(n, sizeof(struct dst_trans));
+ if (err)
+ return err;
+
+ err = dst_node_create_disk(n);
+ if (err)
+ return err;
+
+ dst_node_set_size(n);
+ add_disk(n->disk);
+
+ dprintk("DST: started remote node '%s', minor: %d.\n", n->name, n->disk->first_minor);
+
+ return 0;
+}
+
+/*
+ * Adding remote node and initialize connection.
+ */
+static int dst_add_remote(struct dst_node *n, struct dst_ctl *ctl,
+ void *data, unsigned int size)
+{
+ int err;
+ struct dst_network_ctl *rctl = data;
+
+ if (n)
+ return -EEXIST;
+
+ if (size != sizeof(struct dst_network_ctl))
+ return -EINVAL;
+
+ n = dst_alloc_node(ctl, dst_start_remote, 1);
+ if (!n)
+ return -ENOMEM;
+
+ memcpy(&n->info->net, rctl, sizeof(struct dst_network_ctl));
+ err = dst_node_init_connected(n, rctl);
+ if (err)
+ goto err_out_free;
+
+ dst_node_add(n);
+
+ return 0;
+
+err_out_free:
+ dst_node_put(n);
+ return err;
+}
+
+/*
+ * Adding export node: initializing block device and listening socket.
+ */
+static int dst_add_export(struct dst_node *n, struct dst_ctl *ctl,
+ void *data, unsigned int size)
+{
+ int err;
+ struct dst_export_ctl *le = data;
+
+ if (n)
+ return -EEXIST;
+
+ if (size != sizeof(struct dst_export_ctl))
+ return -EINVAL;
+
+ n = dst_alloc_node(ctl, dst_start_export, 2);
+ if (!n)
+ return -EINVAL;
+
+ err = dst_setup_export(n, ctl, le);
+ if (err)
+ goto err_out_free;
+
+ dst_node_add(n);
+
+ return 0;
+
+err_out_free:
+ dst_node_put(n);
+ return err;
+}
+
+static int dst_node_remove_unload(struct dst_node *n)
+{
+ printk(KERN_INFO "STOPPED name: '%s', size: %llu.\n",
+ n->name, n->size);
+
+ if (n->disk)
+ del_gendisk(n->disk);
+
+ dst_node_remove(n);
+ dst_node_sysfs_exit(n);
+
+ /*
+ * This is not a hack. Really.
+ * Node's reference counter allows to implement fine grained
+ * node freeing, but since all transactions (which hold node's
+ * reference counter) are processed in the dedicated thread,
+ * it is possible that reference will hit zero in that thread,
+ * so we will not be able to exit thread and cleanup the node.
+ *
+ * So, we remove disk, so no new activity is possible, and
+ * wait until all pending transaction are completed (either
+ * in receiving thread or by timeout in workqueue), in this
+ * case reference counter will be less or equal to 2 (once set in
+ * dst_alloc_node() and then in connector message parser;
+ * or when we force module unloading, and connector message
+ * parser does not hold a reference, in this case reference
+ * counter will be equal to 1),
+ * and subsequent dst_node_put() calls will free the node.
+ */
+ dprintk("%s: going to sleep with %d refcnt.\n", __func__, atomic_read(&n->refcnt));
+ wait_event(n->wait, atomic_read(&n->refcnt) <= 2);
+
+ dst_node_put(n);
+ return 0;
+}
+
+/*
+ * Remove node from the hash table.
+ */
+static int dst_del_node(struct dst_node *n, struct dst_ctl *ctl,
+ void *data, unsigned int size)
+{
+ if (!n)
+ return -ENODEV;
+
+ return dst_node_remove_unload(n);
+}
+
+/*
+ * Initialize crypto processing for given node.
+ */
+static int dst_crypto_init(struct dst_node *n, struct dst_ctl *ctl,
+ void *data, unsigned int size)
+{
+ struct dst_crypto_ctl *crypto = data;
+
+ if (!n)
+ return -ENODEV;
+
+ if (size != sizeof(struct dst_crypto_ctl) + crypto->hash_keysize +
+ crypto->cipher_keysize)
+ return -EINVAL;
+
+ if (n->trans_cache)
+ return -EEXIST;
+
+ return dst_node_crypto_init(n, crypto);
+}
+
+/*
+ * Security attributes for given node.
+ */
+static int dst_security_init(struct dst_node *n, struct dst_ctl *ctl,
+ void *data, unsigned int size)
+{
+ struct dst_secure *s;
+
+ if (!n)
+ return -ENODEV;
+
+ if (size != sizeof(struct dst_secure_user))
+ return -EINVAL;
+
+ s = kmalloc(sizeof(struct dst_secure), GFP_KERNEL);
+ if (!s)
+ return -ENOMEM;
+
+ memcpy(&s->sec, data, size);
+
+ mutex_lock(&n->security_lock);
+ list_add_tail(&s->sec_entry, &n->security_list);
+ mutex_unlock(&n->security_lock);
+
+ return 0;
+}
+
+/*
+ * Kill'em all!
+ */
+static int dst_start_node(struct dst_node *n, struct dst_ctl *ctl,
+ void *data, unsigned int size)
+{
+ int err;
+
+ if (!n)
+ return -ENODEV;
+
+ if (n->trans_cache)
+ return 0;
+
+ err = n->start(n);
+ if (err)
+ return err;
+
+ printk(KERN_INFO "STARTED name: '%s', size: %llu.\n", n->name, n->size);
+ return 0;
+}
+
+typedef int (*dst_command_func)(struct dst_node *n, struct dst_ctl *ctl,
+ void *data, unsigned int size);
+
+/*
+ * List of userspace commands.
+ */
+static dst_command_func dst_commands[] = {
+ [DST_ADD_REMOTE] = &dst_add_remote,
+ [DST_ADD_EXPORT] = &dst_add_export,
+ [DST_DEL_NODE] = &dst_del_node,
+ [DST_CRYPTO] = &dst_crypto_init,
+ [DST_SECURITY] = &dst_security_init,
+ [DST_START] = &dst_start_node,
+};
+
+/*
+ * Configuration parser.
+ */
+static void cn_dst_callback(void *data)
+{
+ struct dst_ctl *ctl;
+ struct cn_msg *msg = data;
+ int err;
+ struct dst_ctl_ack ack;
+ struct dst_node *n = NULL, *tmp;
+ unsigned int hash;
+
+ if (msg->len < sizeof(struct dst_ctl)) {
+ err = -EBADMSG;
+ goto out;
+ }
+
+ ctl = (struct dst_ctl *)msg->data;
+
+ if (ctl->cmd >= DST_CMD_MAX) {
+ err = -EINVAL;
+ goto out;
+ }
+ hash = dst_hash(ctl->name, sizeof(ctl->name));
+
+ mutex_lock(&dst_hash_lock);
+ list_for_each_entry(tmp, &dst_hashtable[hash], node_entry) {
+ if (!memcmp(tmp->name, ctl->name, sizeof(tmp->name))) {
+ n = tmp;
+ dst_node_get(n);
+ break;
+ }
+ }
+ mutex_unlock(&dst_hash_lock);
+
+ err = dst_commands[ctl->cmd](n, ctl, msg->data + sizeof(struct dst_ctl),
+ msg->len - sizeof(struct dst_ctl));
+
+ dst_node_put(n);
+out:
+ memcpy(&ack.msg, msg, sizeof(struct cn_msg));
+
+ ack.msg.ack = msg->ack + 1;
+ ack.msg.len = sizeof(struct dst_ctl_ack) - sizeof(struct cn_msg);
+
+ ack.error = err;
+
+ cn_netlink_send(&ack.msg, 0, GFP_KERNEL);
+}
+
+/*
+ * Global initialization: sysfs, hash table, block device registration,
+ * connector and various caches.
+ */
+static int __init dst_sysfs_init(void)
+{
+ return bus_register(&dst_dev_bus_type);
+}
+
+static void dst_sysfs_exit(void)
+{
+ bus_unregister(&dst_dev_bus_type);
+}
+
+static int __init dst_hashtable_init(void)
+{
+ unsigned int i;
+
+ dst_hashtable = kcalloc(dst_hashtable_size, sizeof(struct list_head),
+ GFP_KERNEL);
+ if (!dst_hashtable)
+ return -ENOMEM;
+
+ for (i=0; i<dst_hashtable_size; ++i)
+ INIT_LIST_HEAD(&dst_hashtable[i]);
+
+ return 0;
+}
+
+static void dst_hashtable_exit(void)
+{
+ unsigned int i;
+ struct dst_node *n, *tmp;
+
+ for (i=0; i<dst_hashtable_size; ++i) {
+ list_for_each_entry_safe(n, tmp, &dst_hashtable[i], node_entry) {
+ dst_node_remove_unload(n);
+ }
+ }
+
+ kfree(dst_hashtable);
+}
+
+static int __init dst_sys_init(void)
+{
+ int err = -ENOMEM;
+
+ err = dst_hashtable_init();
+ if (err)
+ goto err_out_exit;
+
+ err = dst_export_init();
+ if (err)
+ goto err_out_hashtable_exit;
+
+ err = register_blkdev(dst_major, DST_NAME);
+ if (err < 0)
+ goto err_out_export_exit;
+ if (err)
+ dst_major = err;
+
+ err = dst_sysfs_init();
+ if (err)
+ goto err_out_unregister;
+
+ err = cn_add_callback(&cn_dst_id, "DST", cn_dst_callback);
+ if (err)
+ goto err_out_sysfs_exit;
+
+ printk(KERN_INFO "Distributed storage, '%s' release.\n", dst_name);
+
+ return 0;
+
+err_out_sysfs_exit:
+ dst_sysfs_exit();
+err_out_unregister:
+ unregister_blkdev(dst_major, DST_NAME);
+err_out_export_exit:
+ dst_export_exit();
+err_out_hashtable_exit:
+ dst_hashtable_exit();
+err_out_exit:
+ return err;
+}
+
+static void __exit dst_sys_exit(void)
+{
+ cn_del_callback(&cn_dst_id);
+ unregister_blkdev(dst_major, DST_NAME);
+ dst_hashtable_exit();
+ dst_sysfs_exit();
+ dst_export_exit();
+}
+
+module_init(dst_sys_init);
+module_exit(dst_sys_exit);
+
+MODULE_DESCRIPTION("Distributed storage");
+MODULE_AUTHOR("Evgeniy Polyakov <zbr@ioremap.net>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/dst/export.c b/drivers/staging/dst/export.c
new file mode 100644
index 000000000000..122fe7577dcb
--- /dev/null
+++ b/drivers/staging/dst/export.c
@@ -0,0 +1,664 @@
+/*
+ * 2007+ Copyright (c) Evgeniy Polyakov <zbr@ioremap.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.
+ */
+
+#include <linux/blkdev.h>
+#include <linux/bio.h>
+#include <linux/dst.h>
+#include <linux/in.h>
+#include <linux/in6.h>
+#include <linux/poll.h>
+#include <linux/slab.h>
+#include <linux/socket.h>
+
+#include <net/sock.h>
+
+/*
+ * Export bioset is used for server block IO requests.
+ */
+static struct bio_set *dst_bio_set;
+
+int __init dst_export_init(void)
+{
+ int err = -ENOMEM;
+
+ dst_bio_set = bioset_create(32, 32);
+ if (!dst_bio_set)
+ goto err_out_exit;
+
+ return 0;
+
+err_out_exit:
+ return err;
+}
+
+void dst_export_exit(void)
+{
+ bioset_free(dst_bio_set);
+}
+
+/*
+ * When client connects and autonegotiates with the server node,
+ * its permissions are checked in a security attributes and sent
+ * back.
+ */
+static unsigned int dst_check_permissions(struct dst_state *main, struct dst_state *st)
+{
+ struct dst_node *n = main->node;
+ struct dst_secure *sentry;
+ struct dst_secure_user *s;
+ struct saddr *sa = &st->ctl.addr;
+ unsigned int perm = 0;
+
+ mutex_lock(&n->security_lock);
+ list_for_each_entry(sentry, &n->security_list, sec_entry) {
+ s = &sentry->sec;
+
+ if (s->addr.sa_family != sa->sa_family)
+ continue;
+
+ if (s->addr.sa_data_len != sa->sa_data_len)
+ continue;
+
+ /*
+ * This '2' below is a port field. This may be very wrong to do
+ * in atalk for example though. If there will be any need to extent
+ * protocol to something else, I can create per-family helpers and
+ * use them instead of this memcmp.
+ */
+ if (memcmp(s->addr.sa_data + 2, sa->sa_data + 2,
+ sa->sa_data_len - 2))
+ continue;
+
+ perm = s->permissions;
+ }
+ mutex_unlock(&n->security_lock);
+
+ return perm;
+}
+
+/*
+ * Accept new client: allocate appropriate network state and check permissions.
+ */
+static struct dst_state *dst_accept_client(struct dst_state *st)
+{
+ unsigned int revents = 0;
+ unsigned int err_mask = POLLERR | POLLHUP | POLLRDHUP;
+ unsigned int mask = err_mask | POLLIN;
+ struct dst_node *n = st->node;
+ int err = 0;
+ struct socket *sock = NULL;
+ struct dst_state *new;
+
+ while (!err && !sock) {
+ revents = dst_state_poll(st);
+
+ if (!(revents & mask)) {
+ DEFINE_WAIT(wait);
+
+ for (;;) {
+ prepare_to_wait(&st->thread_wait,
+ &wait, TASK_INTERRUPTIBLE);
+ if (!n->trans_scan_timeout || st->need_exit)
+ break;
+
+ revents = dst_state_poll(st);
+
+ if (revents & mask)
+ break;
+
+ if (signal_pending(current))
+ break;
+
+ /*
+ * Magic HZ? Polling check above is not safe in
+ * all cases (like socket reset in BH context),
+ * so it is simpler just to postpone it to the
+ * process context instead of implementing special
+ * locking there.
+ */
+ schedule_timeout(HZ);
+ }
+ finish_wait(&st->thread_wait, &wait);
+ }
+
+ err = -ECONNRESET;
+ dst_state_lock(st);
+
+ dprintk("%s: st: %p, revents: %x [err: %d, in: %d].\n",
+ __func__, st, revents, revents & err_mask,
+ revents & POLLIN);
+
+ if (revents & err_mask) {
+ dprintk("%s: revents: %x, socket: %p, err: %d.\n",
+ __func__, revents, st->socket, err);
+ err = -ECONNRESET;
+ }
+
+ if (!n->trans_scan_timeout || st->need_exit)
+ err = -ENODEV;
+
+ if (st->socket && (revents & POLLIN))
+ err = kernel_accept(st->socket, &sock, 0);
+
+ dst_state_unlock(st);
+ }
+
+ if (err)
+ goto err_out_exit;
+
+ new = dst_state_alloc(st->node);
+ if (!new) {
+ err = -ENOMEM;
+ goto err_out_release;
+ }
+ new->socket = sock;
+
+ new->ctl.addr.sa_data_len = sizeof(struct sockaddr);
+ err = kernel_getpeername(sock, (struct sockaddr *)&new->ctl.addr,
+ (int *)&new->ctl.addr.sa_data_len);
+ if (err)
+ goto err_out_put;
+
+ new->permissions = dst_check_permissions(st, new);
+ if (new->permissions == 0) {
+ err = -EPERM;
+ dst_dump_addr(sock, (struct sockaddr *)&new->ctl.addr,
+ "Client is not allowed to connect");
+ goto err_out_put;
+ }
+
+ err = dst_poll_init(new);
+ if (err)
+ goto err_out_put;
+
+ dst_dump_addr(sock, (struct sockaddr *)&new->ctl.addr,
+ "Connected client");
+
+ return new;
+
+err_out_put:
+ dst_state_put(new);
+err_out_release:
+ sock_release(sock);
+err_out_exit:
+ return ERR_PTR(err);
+}
+
+/*
+ * Each server's block request sometime finishes.
+ * Usually it happens in hard irq context of the appropriate controller,
+ * so to play good with all cases we just queue BIO into the queue
+ * and wake up processing thread, which gets completed request and
+ * send (encrypting if needed) it back to the client (if it was a read
+ * request), or sends back reply that writing succesfully completed.
+ */
+static int dst_export_process_request_queue(struct dst_state *st)
+{
+ unsigned long flags;
+ struct dst_export_priv *p = NULL;
+ struct bio *bio;
+ int err = 0;
+
+ while (!list_empty(&st->request_list)) {
+ spin_lock_irqsave(&st->request_lock, flags);
+ if (!list_empty(&st->request_list)) {
+ p = list_first_entry(&st->request_list,
+ struct dst_export_priv, request_entry);
+ list_del(&p->request_entry);
+ }
+ spin_unlock_irqrestore(&st->request_lock, flags);
+
+ if (!p)
+ break;
+
+ bio = p->bio;
+
+ if (dst_need_crypto(st->node) && (bio_data_dir(bio) == READ))
+ err = dst_export_crypto(st->node, bio);
+ else
+ err = dst_export_send_bio(bio);
+
+ if (err)
+ break;
+ }
+
+ return err;
+}
+
+/*
+ * Cleanup export state.
+ * It has to wait until all requests are finished,
+ * and then free them all.
+ */
+static void dst_state_cleanup_export(struct dst_state *st)
+{
+ struct dst_export_priv *p;
+ unsigned long flags;
+
+ /*
+ * This loop waits for all pending bios to be completed and freed.
+ */
+ while (atomic_read(&st->refcnt) > 1) {
+ dprintk("%s: st: %p, refcnt: %d, list_empty: %d.\n",
+ __func__, st, atomic_read(&st->refcnt),
+ list_empty(&st->request_list));
+ wait_event_timeout(st->thread_wait,
+ (atomic_read(&st->refcnt) == 1) ||
+ !list_empty(&st->request_list),
+ HZ/2);
+
+ while (!list_empty(&st->request_list)) {
+ p = NULL;
+ spin_lock_irqsave(&st->request_lock, flags);
+ if (!list_empty(&st->request_list)) {
+ p = list_first_entry(&st->request_list,
+ struct dst_export_priv, request_entry);
+ list_del(&p->request_entry);
+ }
+ spin_unlock_irqrestore(&st->request_lock, flags);
+
+ if (p)
+ bio_put(p->bio);
+
+ dprintk("%s: st: %p, refcnt: %d, list_empty: %d, p: %p.\n",
+ __func__, st, atomic_read(&st->refcnt),
+ list_empty(&st->request_list), p);
+ }
+ }
+
+ dst_state_put(st);
+}
+
+/*
+ * Client accepting thread.
+ * Not only accepts new connection, but also schedules receiving thread
+ * and performs request completion described above.
+ */
+static int dst_accept(void *init_data, void *schedule_data)
+{
+ struct dst_state *main_st = schedule_data;
+ struct dst_node *n = init_data;
+ struct dst_state *st;
+ int err;
+
+ while (n->trans_scan_timeout && !main_st->need_exit) {
+ dprintk("%s: main_st: %p, n: %p.\n", __func__, main_st, n);
+ st = dst_accept_client(main_st);
+ if (IS_ERR(st))
+ continue;
+
+ err = dst_state_schedule_receiver(st);
+ if (!err) {
+ while (n->trans_scan_timeout) {
+ err = wait_event_interruptible_timeout(st->thread_wait,
+ !list_empty(&st->request_list) ||
+ !n->trans_scan_timeout ||
+ st->need_exit,
+ HZ);
+
+ if (!n->trans_scan_timeout || st->need_exit)
+ break;
+
+ if (list_empty(&st->request_list))
+ continue;
+
+ err = dst_export_process_request_queue(st);
+ if (err)
+ break;
+ }
+
+ st->need_exit = 1;
+ wake_up(&st->thread_wait);
+ }
+
+ dst_state_cleanup_export(st);
+ }
+
+ dprintk("%s: freeing listening socket st: %p.\n", __func__, main_st);
+
+ dst_state_lock(main_st);
+ dst_poll_exit(main_st);
+ dst_state_socket_release(main_st);
+ dst_state_unlock(main_st);
+ dst_state_put(main_st);
+ dprintk("%s: freed listening socket st: %p.\n", __func__, main_st);
+
+ return 0;
+}
+
+int dst_start_export(struct dst_node *n)
+{
+ if (list_empty(&n->security_list)) {
+ printk(KERN_ERR "You are trying to export node '%s' without security attributes.\n"
+ "No clients will be allowed to connect. Exiting.\n", n->name);
+ return -EINVAL;
+ }
+ return dst_node_trans_init(n, sizeof(struct dst_export_priv));
+}
+
+/*
+ * Initialize listening state and schedule accepting thread.
+ */
+int dst_node_init_listened(struct dst_node *n, struct dst_export_ctl *le)
+{
+ struct dst_state *st;
+ int err = -ENOMEM;
+ struct dst_network_ctl *ctl = &le->ctl;
+
+ memcpy(&n->info->net, ctl, sizeof(struct dst_network_ctl));
+
+ st = dst_state_alloc(n);
+ if (IS_ERR(st)) {
+ err = PTR_ERR(st);
+ goto err_out_exit;
+ }
+ memcpy(&st->ctl, ctl, sizeof(struct dst_network_ctl));
+
+ err = dst_state_socket_create(st);
+ if (err)
+ goto err_out_put;
+
+ st->socket->sk->sk_reuse = 1;
+
+ err = kernel_bind(st->socket, (struct sockaddr *)&ctl->addr,
+ ctl->addr.sa_data_len);
+ if (err)
+ goto err_out_socket_release;
+
+ err = kernel_listen(st->socket, 1024);
+ if (err)
+ goto err_out_socket_release;
+ n->state = st;
+
+ err = dst_poll_init(st);
+ if (err)
+ goto err_out_socket_release;
+
+ dst_state_get(st);
+
+ err = thread_pool_schedule(n->pool, dst_thread_setup,
+ dst_accept, st, MAX_SCHEDULE_TIMEOUT);
+ if (err)
+ goto err_out_poll_exit;
+
+ return 0;
+
+err_out_poll_exit:
+ dst_poll_exit(st);
+err_out_socket_release:
+ dst_state_socket_release(st);
+err_out_put:
+ dst_state_put(st);
+err_out_exit:
+ n->state = NULL;
+ return err;
+}
+
+/*
+ * Free bio and related private data.
+ * Also drop a reference counter for appropriate state,
+ * which waits when there are no more block IOs in-flight.
+ */
+static void dst_bio_destructor(struct bio *bio)
+{
+ struct bio_vec *bv;
+ struct dst_export_priv *priv = bio->bi_private;
+ int i;
+
+ bio_for_each_segment(bv, bio, i) {
+ if (!bv->bv_page)
+ break;
+
+ __free_page(bv->bv_page);
+ }
+
+ if (priv) {
+ struct dst_node *n = priv->state->node;
+
+ dst_state_put(priv->state);
+ mempool_free(priv, n->trans_pool);
+ }
+ bio_free(bio, dst_bio_set);
+}
+
+/*
+ * Block IO completion. Queue request to be sent back to
+ * the client (or just confirmation).
+ */
+static void dst_bio_end_io(struct bio *bio, int err)
+{
+ struct dst_export_priv *p = bio->bi_private;
+ struct dst_state *st = p->state;
+ unsigned long flags;
+
+ spin_lock_irqsave(&st->request_lock, flags);
+ list_add_tail(&p->request_entry, &st->request_list);
+ spin_unlock_irqrestore(&st->request_lock, flags);
+
+ wake_up(&st->thread_wait);
+}
+
+/*
+ * Allocate read request for the server.
+ */
+static int dst_export_read_request(struct bio *bio, unsigned int total_size)
+{
+ unsigned int size;
+ struct page *page;
+ int err;
+
+ while (total_size) {
+ err = -ENOMEM;
+ page = alloc_page(GFP_KERNEL);
+ if (!page)
+ goto err_out_exit;
+
+ size = min_t(unsigned int, PAGE_SIZE, total_size);
+
+ err = bio_add_page(bio, page, size, 0);
+ dprintk("%s: bio: %llu/%u, size: %u, err: %d.\n",
+ __func__, (u64)bio->bi_sector, bio->bi_size,
+ size, err);
+ if (err <= 0)
+ goto err_out_free_page;
+
+ total_size -= size;
+ }
+
+ return 0;
+
+err_out_free_page:
+ __free_page(page);
+err_out_exit:
+ return err;
+}
+
+/*
+ * Allocate write request for the server.
+ * Should not only get pages, but also read data from the network.
+ */
+static int dst_export_write_request(struct dst_state *st,
+ struct bio *bio, unsigned int total_size)
+{
+ unsigned int size;
+ struct page *page;
+ void *data;
+ int err;
+
+ while (total_size) {
+ err = -ENOMEM;
+ page = alloc_page(GFP_KERNEL);
+ if (!page)
+ goto err_out_exit;
+
+ data = kmap(page);
+ if (!data)
+ goto err_out_free_page;
+
+ size = min_t(unsigned int, PAGE_SIZE, total_size);
+
+ err = dst_data_recv(st, data, size);
+ if (err)
+ goto err_out_unmap_page;
+
+ err = bio_add_page(bio, page, size, 0);
+ if (err <= 0)
+ goto err_out_unmap_page;
+
+ kunmap(page);
+
+ total_size -= size;
+ }
+
+ return 0;
+
+err_out_unmap_page:
+ kunmap(page);
+err_out_free_page:
+ __free_page(page);
+err_out_exit:
+ return err;
+}
+
+/*
+ * Groovy, we've gotten an IO request from the client.
+ * Allocate BIO from the bioset, private data from the mempool
+ * and lots of pages for IO.
+ */
+int dst_process_io(struct dst_state *st)
+{
+ struct dst_node *n = st->node;
+ struct dst_cmd *cmd = st->data;
+ struct bio *bio;
+ struct dst_export_priv *priv;
+ int err = -ENOMEM;
+
+ if (unlikely(!n->bdev)) {
+ err = -EINVAL;
+ goto err_out_exit;
+ }
+
+ bio = bio_alloc_bioset(GFP_KERNEL,
+ PAGE_ALIGN(cmd->size) >> PAGE_SHIFT,
+ dst_bio_set);
+ if (!bio)
+ goto err_out_exit;
+ bio->bi_private = NULL;
+
+ priv = mempool_alloc(st->node->trans_pool, GFP_KERNEL);
+ if (!priv)
+ goto err_out_free;
+
+ priv->state = dst_state_get(st);
+ priv->bio = bio;
+
+ bio->bi_private = priv;
+ bio->bi_end_io = dst_bio_end_io;
+ bio->bi_destructor = dst_bio_destructor;
+ bio->bi_bdev = n->bdev;
+
+ /*
+ * Server side is only interested in two low bits:
+ * uptodate (set by itself actually) and rw block
+ */
+ bio->bi_flags |= cmd->flags & 3;
+
+ bio->bi_rw = cmd->rw;
+ bio->bi_size = 0;
+ bio->bi_sector = cmd->sector;
+
+ dst_bio_to_cmd(bio, &priv->cmd, DST_IO_RESPONSE, cmd->id);
+
+ priv->cmd.flags = 0;
+ priv->cmd.size = cmd->size;
+
+ if (bio_data_dir(bio) == WRITE) {
+ err = dst_recv_cdata(st, priv->cmd.hash);
+ if (err)
+ goto err_out_free;
+
+ err = dst_export_write_request(st, bio, cmd->size);
+ if (err)
+ goto err_out_free;
+
+ if (dst_need_crypto(n))
+ return dst_export_crypto(n, bio);
+ } else {
+ err = dst_export_read_request(bio, cmd->size);
+ if (err)
+ goto err_out_free;
+ }
+
+ dprintk("%s: bio: %llu/%u, rw: %lu, dir: %lu, flags: %lx, phys: %d.\n",
+ __func__, (u64)bio->bi_sector, bio->bi_size,
+ bio->bi_rw, bio_data_dir(bio),
+ bio->bi_flags, bio->bi_phys_segments);
+
+ generic_make_request(bio);
+
+ return 0;
+
+err_out_free:
+ bio_put(bio);
+err_out_exit:
+ return err;
+}
+
+/*
+ * Ok, block IO is ready, let's send it back to the client...
+ */
+int dst_export_send_bio(struct bio *bio)
+{
+ struct dst_export_priv *p = bio->bi_private;
+ struct dst_state *st = p->state;
+ struct dst_cmd *cmd = &p->cmd;
+ int err;
+
+ dprintk("%s: id: %llu, bio: %llu/%u, csize: %u, flags: %lu, rw: %lu.\n",
+ __func__, cmd->id, (u64)bio->bi_sector, bio->bi_size,
+ cmd->csize, bio->bi_flags, bio->bi_rw);
+
+ dst_convert_cmd(cmd);
+
+ dst_state_lock(st);
+ if (!st->socket) {
+ err = -ECONNRESET;
+ goto err_out_unlock;
+ }
+
+ if (bio_data_dir(bio) == WRITE) {
+ /* ... or just confirmation that writing has completed. */
+ cmd->size = cmd->csize = 0;
+ err = dst_data_send_header(st->socket, cmd,
+ sizeof(struct dst_cmd), 0);
+ if (err)
+ goto err_out_unlock;
+ } else {
+ err = dst_send_bio(st, cmd, bio);
+ if (err)
+ goto err_out_unlock;
+ }
+
+ dst_state_unlock(st);
+
+ bio_put(bio);
+ return 0;
+
+err_out_unlock:
+ dst_state_unlock(st);
+
+ bio_put(bio);
+ return err;
+}
diff --git a/drivers/staging/dst/state.c b/drivers/staging/dst/state.c
new file mode 100644
index 000000000000..d057e52f3b64
--- /dev/null
+++ b/drivers/staging/dst/state.c
@@ -0,0 +1,839 @@
+/*
+ * 2007+ Copyright (c) Evgeniy Polyakov <zbr@ioremap.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.
+ */
+
+#include <linux/buffer_head.h>
+#include <linux/blkdev.h>
+#include <linux/bio.h>
+#include <linux/connector.h>
+#include <linux/dst.h>
+#include <linux/device.h>
+#include <linux/in.h>
+#include <linux/in6.h>
+#include <linux/socket.h>
+#include <linux/slab.h>
+
+#include <net/sock.h>
+
+/*
+ * Polling machinery.
+ */
+
+struct dst_poll_helper
+{
+ poll_table pt;
+ struct dst_state *st;
+};
+
+static int dst_queue_wake(wait_queue_t *wait, unsigned mode, int sync, void *key)
+{
+ struct dst_state *st = container_of(wait, struct dst_state, wait);
+
+ wake_up(&st->thread_wait);
+ return 1;
+}
+
+static void dst_queue_func(struct file *file, wait_queue_head_t *whead,
+ poll_table *pt)
+{
+ struct dst_state *st = container_of(pt, struct dst_poll_helper, pt)->st;
+
+ st->whead = whead;
+ init_waitqueue_func_entry(&st->wait, dst_queue_wake);
+ add_wait_queue(whead, &st->wait);
+}
+
+void dst_poll_exit(struct dst_state *st)
+{
+ if (st->whead) {
+ remove_wait_queue(st->whead, &st->wait);
+ st->whead = NULL;
+ }
+}
+
+int dst_poll_init(struct dst_state *st)
+{
+ struct dst_poll_helper ph;
+
+ ph.st = st;
+ init_poll_funcptr(&ph.pt, &dst_queue_func);
+
+ st->socket->ops->poll(NULL, st->socket, &ph.pt);
+ return 0;
+}
+
+/*
+ * Header receiving function - may block.
+ */
+static int dst_data_recv_header(struct socket *sock,
+ void *data, unsigned int size, int block)
+{
+ struct msghdr msg;
+ struct kvec iov;
+ int err;
+
+ iov.iov_base = data;
+ iov.iov_len = size;
+
+ msg.msg_iov = (struct iovec *)&iov;
+ msg.msg_iovlen = 1;
+ msg.msg_name = NULL;
+ msg.msg_namelen = 0;
+ msg.msg_control = NULL;
+ msg.msg_controllen = 0;
+ msg.msg_flags = (block)?MSG_WAITALL:MSG_DONTWAIT;
+
+ err = kernel_recvmsg(sock, &msg, &iov, 1, iov.iov_len,
+ msg.msg_flags);
+ if (err != size)
+ return -1;
+
+ return 0;
+}
+
+/*
+ * Header sending function - may block.
+ */
+int dst_data_send_header(struct socket *sock,
+ void *data, unsigned int size, int more)
+{
+ struct msghdr msg;
+ struct kvec iov;
+ int err;
+
+ iov.iov_base = data;
+ iov.iov_len = size;
+
+ msg.msg_iov = (struct iovec *)&iov;
+ msg.msg_iovlen = 1;
+ msg.msg_name = NULL;
+ msg.msg_namelen = 0;
+ msg.msg_control = NULL;
+ msg.msg_controllen = 0;
+ msg.msg_flags = MSG_WAITALL | (more)?MSG_MORE:0;
+
+ err = kernel_sendmsg(sock, &msg, &iov, 1, iov.iov_len);
+ if (err != size) {
+ dprintk("%s: size: %u, more: %d, err: %d.\n",
+ __func__, size, more, err);
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Block autoconfiguration: request size of the storage and permissions.
+ */
+static int dst_request_remote_config(struct dst_state *st)
+{
+ struct dst_node *n = st->node;
+ int err = -EINVAL;
+ struct dst_cmd *cmd = st->data;
+
+ memset(cmd, 0, sizeof(struct dst_cmd));
+ cmd->cmd = DST_CFG;
+
+ dst_convert_cmd(cmd);
+
+ err = dst_data_send_header(st->socket, cmd, sizeof(struct dst_cmd), 0);
+ if (err)
+ goto out;
+
+ err = dst_data_recv_header(st->socket, cmd, sizeof(struct dst_cmd), 1);
+ if (err)
+ goto out;
+
+ dst_convert_cmd(cmd);
+
+ if (cmd->cmd != DST_CFG) {
+ err = -EINVAL;
+ dprintk("%s: checking result: cmd: %d, size reported: %llu.\n",
+ __func__, cmd->cmd, cmd->sector);
+ goto out;
+ }
+
+ if (n->size != 0)
+ n->size = min_t(loff_t, n->size, cmd->sector);
+ else
+ n->size = cmd->sector;
+
+ n->info->size = n->size;
+ st->permissions = cmd->rw;
+
+out:
+ dprintk("%s: n: %p, err: %d, size: %llu, permission: %x.\n",
+ __func__, n, err, n->size, st->permissions);
+ return err;
+}
+
+/*
+ * Socket machinery.
+ */
+
+#define DST_DEFAULT_TIMEO 20000
+
+int dst_state_socket_create(struct dst_state *st)
+{
+ int err;
+ struct socket *sock;
+ struct dst_network_ctl *ctl = &st->ctl;
+
+ err = sock_create(ctl->addr.sa_family, ctl->type, ctl->proto, &sock);
+ if (err < 0)
+ return err;
+
+ sock->sk->sk_sndtimeo = sock->sk->sk_rcvtimeo =
+ msecs_to_jiffies(DST_DEFAULT_TIMEO);
+ sock->sk->sk_allocation = GFP_NOIO;
+
+ st->socket = st->read_socket = sock;
+ return 0;
+}
+
+void dst_state_socket_release(struct dst_state *st)
+{
+ dprintk("%s: st: %p, socket: %p, n: %p.\n",
+ __func__, st, st->socket, st->node);
+ if (st->socket) {
+ sock_release(st->socket);
+ st->socket = NULL;
+ st->read_socket = NULL;
+ }
+}
+
+void dst_dump_addr(struct socket *sk, struct sockaddr *sa, char *str)
+{
+ if (sk->ops->family == AF_INET) {
+ struct sockaddr_in *sin = (struct sockaddr_in *)sa;
+ printk(KERN_INFO "%s %u.%u.%u.%u:%d.\n",
+ str, NIPQUAD(sin->sin_addr.s_addr), ntohs(sin->sin_port));
+ } else if (sk->ops->family == AF_INET6) {
+ struct sockaddr_in6 *sin = (struct sockaddr_in6 *)sa;
+ printk(KERN_INFO "%s %pi6:%d",
+ str, &sin->sin6_addr, ntohs(sin->sin6_port));
+ }
+}
+
+void dst_state_exit_connected(struct dst_state *st)
+{
+ if (st->socket) {
+ dst_poll_exit(st);
+ st->socket->ops->shutdown(st->socket, 2);
+
+ dst_dump_addr(st->socket, (struct sockaddr *)&st->ctl.addr,
+ "Disconnected peer");
+ dst_state_socket_release(st);
+ }
+}
+
+static int dst_state_init_connected(struct dst_state *st)
+{
+ int err;
+ struct dst_network_ctl *ctl = &st->ctl;
+
+ err = dst_state_socket_create(st);
+ if (err)
+ goto err_out_exit;
+
+ err = kernel_connect(st->socket, (struct sockaddr *)&st->ctl.addr,
+ st->ctl.addr.sa_data_len, 0);
+ if (err)
+ goto err_out_release;
+
+ err = dst_poll_init(st);
+ if (err)
+ goto err_out_release;
+
+ dst_dump_addr(st->socket, (struct sockaddr *)&ctl->addr,
+ "Connected to peer");
+
+ return 0;
+
+err_out_release:
+ dst_state_socket_release(st);
+err_out_exit:
+ return err;
+}
+
+/*
+ * State reset is used to reconnect to the remote peer.
+ * May fail, but who cares, we will try again later.
+ */
+static void inline dst_state_reset_nolock(struct dst_state *st)
+{
+ dst_state_exit_connected(st);
+ dst_state_init_connected(st);
+}
+
+static void inline dst_state_reset(struct dst_state *st)
+{
+ dst_state_lock(st);
+ dst_state_reset_nolock(st);
+ dst_state_unlock(st);
+}
+
+/*
+ * Basic network sending/receiving functions.
+ * Blocked mode is used.
+ */
+static int dst_data_recv_raw(struct dst_state *st, void *buf, u64 size)
+{
+ struct msghdr msg;
+ struct kvec iov;
+ int err;
+
+ BUG_ON(!size);
+
+ iov.iov_base = buf;
+ iov.iov_len = size;
+
+ msg.msg_iov = (struct iovec *)&iov;
+ msg.msg_iovlen = 1;
+ msg.msg_name = NULL;
+ msg.msg_namelen = 0;
+ msg.msg_control = NULL;
+ msg.msg_controllen = 0;
+ msg.msg_flags = MSG_DONTWAIT;
+
+ err = kernel_recvmsg(st->socket, &msg, &iov, 1, iov.iov_len,
+ msg.msg_flags);
+ if (err <= 0) {
+ dprintk("%s: failed to recv data: size: %llu, err: %d.\n",
+ __func__, size, err);
+ if (err == 0)
+ err = -ECONNRESET;
+
+ dst_state_exit_connected(st);
+ }
+
+ return err;
+}
+
+/*
+ * Ping command to early detect failed nodes.
+ */
+static int dst_send_ping(struct dst_state *st)
+{
+ struct dst_cmd *cmd = st->data;
+ int err = -ECONNRESET;
+
+ dst_state_lock(st);
+ if (st->socket) {
+ memset(cmd, 0, sizeof(struct dst_cmd));
+
+ cmd->cmd = __cpu_to_be32(DST_PING);
+
+ err = dst_data_send_header(st->socket, cmd, sizeof(struct dst_cmd), 0);
+ }
+ dprintk("%s: st: %p, socket: %p, err: %d.\n", __func__, st, st->socket, err);
+ dst_state_unlock(st);
+
+ return err;
+}
+
+/*
+ * Receiving function, which should either return error or read
+ * whole block request. If there was no traffic for a one second,
+ * send a ping, since remote node may die.
+ */
+int dst_data_recv(struct dst_state *st, void *data, unsigned int size)
+{
+ unsigned int revents = 0;
+ unsigned int err_mask = POLLERR | POLLHUP | POLLRDHUP;
+ unsigned int mask = err_mask | POLLIN;
+ struct dst_node *n = st->node;
+ int err = 0;
+
+ while (size && !err) {
+ revents = dst_state_poll(st);
+
+ if (!(revents & mask)) {
+ DEFINE_WAIT(wait);
+
+ for (;;) {
+ prepare_to_wait(&st->thread_wait, &wait,
+ TASK_INTERRUPTIBLE);
+ if (!n->trans_scan_timeout || st->need_exit)
+ break;
+
+ revents = dst_state_poll(st);
+
+ if (revents & mask)
+ break;
+
+ if (signal_pending(current))
+ break;
+
+ if (!schedule_timeout(HZ)) {
+ err = dst_send_ping(st);
+ if (err)
+ return err;
+ }
+
+ continue;
+ }
+ finish_wait(&st->thread_wait, &wait);
+ }
+
+ err = -ECONNRESET;
+ dst_state_lock(st);
+
+ if ( st->socket &&
+ (st->read_socket == st->socket) &&
+ (revents & POLLIN)) {
+ err = dst_data_recv_raw(st, data, size);
+ if (err > 0) {
+ data += err;
+ size -= err;
+ err = 0;
+ }
+ }
+
+ if (revents & err_mask || !st->socket) {
+ dprintk("%s: revents: %x, socket: %p, size: %u, err: %d.\n",
+ __func__, revents, st->socket, size, err);
+ err = -ECONNRESET;
+ }
+
+ dst_state_unlock(st);
+
+ if (!n->trans_scan_timeout)
+ err = -ENODEV;
+ }
+
+ return err;
+}
+
+/*
+ * Send block autoconf reply.
+ */
+static int dst_process_cfg(struct dst_state *st)
+{
+ struct dst_node *n = st->node;
+ struct dst_cmd *cmd = st->data;
+ int err;
+
+ cmd->sector = n->size;
+ cmd->rw = st->permissions;
+
+ dst_convert_cmd(cmd);
+
+ dst_state_lock(st);
+ err = dst_data_send_header(st->socket, cmd, sizeof(struct dst_cmd), 0);
+ dst_state_unlock(st);
+
+ return err;
+}
+
+/*
+ * Receive block IO from the network.
+ */
+static int dst_recv_bio(struct dst_state *st, struct bio *bio, unsigned int total_size)
+{
+ struct bio_vec *bv;
+ int i, err;
+ void *data;
+ unsigned int sz;
+
+ bio_for_each_segment(bv, bio, i) {
+ sz = min(total_size, bv->bv_len);
+
+ dprintk("%s: bio: %llu/%u, total: %u, len: %u, sz: %u, off: %u.\n",
+ __func__, (u64)bio->bi_sector, bio->bi_size, total_size,
+ bv->bv_len, sz, bv->bv_offset);
+
+ data = kmap(bv->bv_page) + bv->bv_offset;
+ err = dst_data_recv(st, data, sz);
+ kunmap(bv->bv_page);
+
+ bv->bv_len = sz;
+
+ if (err)
+ return err;
+
+ total_size -= sz;
+ if (total_size == 0)
+ break;
+ }
+
+ return 0;
+}
+
+/*
+ * Our block IO has just completed and arrived: get it.
+ */
+static int dst_process_io_response(struct dst_state *st)
+{
+ struct dst_node *n = st->node;
+ struct dst_cmd *cmd = st->data;
+ struct dst_trans *t;
+ int err = 0;
+ struct bio *bio;
+
+ mutex_lock(&n->trans_lock);
+ t = dst_trans_search(n, cmd->id);
+ mutex_unlock(&n->trans_lock);
+
+ if (!t)
+ goto err_out_exit;
+
+ bio = t->bio;
+
+ dprintk("%s: bio: %llu/%u, cmd_size: %u, csize: %u, dir: %lu.\n",
+ __func__, (u64)bio->bi_sector, bio->bi_size, cmd->size,
+ cmd->csize, bio_data_dir(bio));
+
+ if (bio_data_dir(bio) == READ) {
+ if (bio->bi_size != cmd->size - cmd->csize)
+ goto err_out_exit;
+
+ if (dst_need_crypto(n)) {
+ err = dst_recv_cdata(st, t->cmd.hash);
+ if (err)
+ goto err_out_exit;
+ }
+
+ err = dst_recv_bio(st, t->bio, bio->bi_size);
+ if (err)
+ goto err_out_exit;
+
+ if (dst_need_crypto(n))
+ return dst_trans_crypto(t);
+ } else {
+ err = -EBADMSG;
+ if (cmd->size || cmd->csize)
+ goto err_out_exit;
+ }
+
+ dst_trans_remove(t);
+ dst_trans_put(t);
+
+ return 0;
+
+err_out_exit:
+ return err;
+}
+
+/*
+ * Receive crypto data.
+ */
+int dst_recv_cdata(struct dst_state *st, void *cdata)
+{
+ struct dst_cmd *cmd = st->data;
+ struct dst_node *n = st->node;
+ struct dst_crypto_ctl *c = &n->crypto;
+ int err;
+
+ if (cmd->csize != c->crypto_attached_size) {
+ dprintk("%s: cmd: cmd: %u, sector: %llu, size: %u, "
+ "csize: %u != digest size %u.\n",
+ __func__, cmd->cmd, cmd->sector, cmd->size,
+ cmd->csize, c->crypto_attached_size);
+ err = -EINVAL;
+ goto err_out_exit;
+ }
+
+ err = dst_data_recv(st, cdata, cmd->csize);
+ if (err)
+ goto err_out_exit;
+
+ cmd->size -= cmd->csize;
+ return 0;
+
+err_out_exit:
+ return err;
+}
+
+/*
+ * Receive the command and start its processing.
+ */
+static int dst_recv_processing(struct dst_state *st)
+{
+ int err = -EINTR;
+ struct dst_cmd *cmd = st->data;
+
+ /*
+ * If socket will be reset after this statement, then
+ * dst_data_recv() will just fail and loop will
+ * start again, so it can be done without any locks.
+ *
+ * st->read_socket is needed to prevents state machine
+ * breaking between this data reading and subsequent one
+ * in protocol specific functions during connection reset.
+ * In case of reset we have to read next command and do
+ * not expect data for old command to magically appear in
+ * new connection.
+ */
+ st->read_socket = st->socket;
+ err = dst_data_recv(st, cmd, sizeof(struct dst_cmd));
+ if (err)
+ goto out_exit;
+
+ dst_convert_cmd(cmd);
+
+ dprintk("%s: cmd: %u, size: %u, csize: %u, id: %llu, "
+ "sector: %llu, flags: %llx, rw: %llx.\n",
+ __func__, cmd->cmd, cmd->size,
+ cmd->csize, cmd->id, cmd->sector,
+ cmd->flags, cmd->rw);
+
+ /*
+ * This should catch protocol breakage and random garbage instead of commands.
+ */
+ if (unlikely(cmd->csize > st->size - sizeof(struct dst_cmd))) {
+ err = -EBADMSG;
+ goto out_exit;
+ }
+
+ err = -EPROTO;
+ switch (cmd->cmd) {
+ case DST_IO_RESPONSE:
+ err = dst_process_io_response(st);
+ break;
+ case DST_IO:
+ err = dst_process_io(st);
+ break;
+ case DST_CFG:
+ err = dst_process_cfg(st);
+ break;
+ case DST_PING:
+ err = 0;
+ break;
+ default:
+ break;
+ }
+
+out_exit:
+ return err;
+}
+
+/*
+ * Receiving thread. For the client node we should try to reconnect,
+ * for accepted client we just drop the state and expect it to reconnect.
+ */
+static int dst_recv(void *init_data, void *schedule_data)
+{
+ struct dst_state *st = schedule_data;
+ struct dst_node *n = init_data;
+ int err = 0;
+
+ dprintk("%s: start st: %p, n: %p, scan: %lu, need_exit: %d.\n",
+ __func__, st, n, n->trans_scan_timeout, st->need_exit);
+
+ while (n->trans_scan_timeout && !st->need_exit) {
+ err = dst_recv_processing(st);
+ if (err < 0) {
+ if (!st->ctl.type)
+ break;
+
+ if (!n->trans_scan_timeout || st->need_exit)
+ break;
+
+ dst_state_reset(st);
+ msleep(1000);
+ }
+ }
+
+ st->need_exit = 1;
+ wake_up(&st->thread_wait);
+
+ dprintk("%s: freeing receiving socket st: %p.\n", __func__, st);
+ dst_state_lock(st);
+ dst_state_exit_connected(st);
+ dst_state_unlock(st);
+ dst_state_put(st);
+
+ dprintk("%s: freed receiving socket st: %p.\n", __func__, st);
+
+ return err;
+}
+
+/*
+ * Network state dies here and borns couple of lines below.
+ * This object is the main network state processing engine:
+ * sending, receiving, reconnections, all network related
+ * tasks are handled on behalf of the state.
+ */
+static void dst_state_free(struct dst_state *st)
+{
+ dprintk("%s: st: %p.\n", __func__, st);
+ if (st->cleanup)
+ st->cleanup(st);
+ kfree(st->data);
+ kfree(st);
+}
+
+struct dst_state *dst_state_alloc(struct dst_node *n)
+{
+ struct dst_state *st;
+ int err = -ENOMEM;
+
+ st = kzalloc(sizeof(struct dst_state), GFP_KERNEL);
+ if (!st)
+ goto err_out_exit;
+
+ st->node = n;
+ st->need_exit = 0;
+
+ st->size = PAGE_SIZE;
+ st->data = kmalloc(st->size, GFP_KERNEL);
+ if (!st->data)
+ goto err_out_free;
+
+ spin_lock_init(&st->request_lock);
+ INIT_LIST_HEAD(&st->request_list);
+
+ mutex_init(&st->state_lock);
+ init_waitqueue_head(&st->thread_wait);
+
+ /*
+ * One for processing thread, another one for node itself.
+ */
+ atomic_set(&st->refcnt, 2);
+
+ dprintk("%s: st: %p, n: %p.\n", __func__, st, st->node);
+
+ return st;
+
+err_out_free:
+ kfree(st);
+err_out_exit:
+ return ERR_PTR(err);
+}
+
+int dst_state_schedule_receiver(struct dst_state *st)
+{
+ return thread_pool_schedule_private(st->node->pool, dst_thread_setup,
+ dst_recv, st, MAX_SCHEDULE_TIMEOUT, st->node);
+}
+
+/*
+ * Initialize client's connection to the remote peer: allocate state,
+ * connect and perform block IO autoconfiguration.
+ */
+int dst_node_init_connected(struct dst_node *n, struct dst_network_ctl *r)
+{
+ struct dst_state *st;
+ int err = -ENOMEM;
+
+ st = dst_state_alloc(n);
+ if (IS_ERR(st)) {
+ err = PTR_ERR(st);
+ goto err_out_exit;
+ }
+ memcpy(&st->ctl, r, sizeof(struct dst_network_ctl));
+
+ err = dst_state_init_connected(st);
+ if (err)
+ goto err_out_free_data;
+
+ err = dst_request_remote_config(st);
+ if (err)
+ goto err_out_exit_connected;
+ n->state = st;
+
+ err = dst_state_schedule_receiver(st);
+ if (err)
+ goto err_out_exit_connected;
+
+ return 0;
+
+err_out_exit_connected:
+ dst_state_exit_connected(st);
+err_out_free_data:
+ dst_state_free(st);
+err_out_exit:
+ n->state = NULL;
+ return err;
+}
+
+void dst_state_put(struct dst_state *st)
+{
+ dprintk("%s: st: %p, refcnt: %d.\n",
+ __func__, st, atomic_read(&st->refcnt));
+ if (atomic_dec_and_test(&st->refcnt))
+ dst_state_free(st);
+}
+
+/*
+ * Send block IO to the network one by one using zero-copy ->sendpage().
+ */
+int dst_send_bio(struct dst_state *st, struct dst_cmd *cmd, struct bio *bio)
+{
+ struct bio_vec *bv;
+ struct dst_crypto_ctl *c = &st->node->crypto;
+ int err, i = 0;
+ int flags = MSG_WAITALL;
+
+ err = dst_data_send_header(st->socket, cmd,
+ sizeof(struct dst_cmd) + c->crypto_attached_size, bio->bi_vcnt);
+ if (err)
+ goto err_out_exit;
+
+ bio_for_each_segment(bv, bio, i) {
+ if (i < bio->bi_vcnt - 1)
+ flags |= MSG_MORE;
+
+ err = kernel_sendpage(st->socket, bv->bv_page, bv->bv_offset,
+ bv->bv_len, flags);
+ if (err <= 0)
+ goto err_out_exit;
+ }
+
+ return 0;
+
+err_out_exit:
+ dprintk("%s: %d/%d, flags: %x, err: %d.\n",
+ __func__, i, bio->bi_vcnt, flags, err);
+ return err;
+}
+
+/*
+ * Send transaction to the remote peer.
+ */
+int dst_trans_send(struct dst_trans *t)
+{
+ int err;
+ struct dst_state *st = t->n->state;
+ struct bio *bio = t->bio;
+
+ dst_convert_cmd(&t->cmd);
+
+ dst_state_lock(st);
+ if (!st->socket) {
+ err = dst_state_init_connected(st);
+ if (err)
+ goto err_out_unlock;
+ }
+
+ if (bio_data_dir(bio) == WRITE) {
+ err = dst_send_bio(st, &t->cmd, t->bio);
+ } else {
+ err = dst_data_send_header(st->socket, &t->cmd,
+ sizeof(struct dst_cmd), 0);
+ }
+ if (err)
+ goto err_out_reset;
+
+ dst_state_unlock(st);
+ return 0;
+
+err_out_reset:
+ dst_state_reset_nolock(st);
+err_out_unlock:
+ dst_state_unlock(st);
+
+ return err;
+}
diff --git a/drivers/staging/dst/thread_pool.c b/drivers/staging/dst/thread_pool.c
new file mode 100644
index 000000000000..c35754d5ec6d
--- /dev/null
+++ b/drivers/staging/dst/thread_pool.c
@@ -0,0 +1,345 @@
+/*
+ * 2007+ Copyright (c) Evgeniy Polyakov <zbr@ioremap.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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/dst.h>
+#include <linux/kthread.h>
+#include <linux/slab.h>
+
+/*
+ * Thread pool abstraction allows to schedule a work to be performed
+ * on behalf of kernel thread. One does not operate with threads itself,
+ * instead user provides setup and cleanup callbacks for thread pool itself,
+ * and action and cleanup callbacks for each submitted work.
+ *
+ * Each worker has private data initialized at creation time and data,
+ * provided by user at scheduling time.
+ *
+ * When action is being performed, thread can not be used by other users,
+ * instead they will sleep until there is free thread to pick their work.
+ */
+struct thread_pool_worker
+{
+ struct list_head worker_entry;
+
+ struct task_struct *thread;
+
+ struct thread_pool *pool;
+
+ int error;
+ int has_data;
+ int need_exit;
+ unsigned int id;
+
+ wait_queue_head_t wait;
+
+ void *private;
+ void *schedule_data;
+
+ int (* action)(void *private, void *schedule_data);
+ void (* cleanup)(void *private);
+};
+
+static void thread_pool_exit_worker(struct thread_pool_worker *w)
+{
+ kthread_stop(w->thread);
+
+ w->cleanup(w->private);
+ kfree(w);
+}
+
+/*
+ * Called to mark thread as ready and allow users to schedule new work.
+ */
+static void thread_pool_worker_make_ready(struct thread_pool_worker *w)
+{
+ struct thread_pool *p = w->pool;
+
+ mutex_lock(&p->thread_lock);
+
+ if (!w->need_exit) {
+ list_move_tail(&w->worker_entry, &p->ready_list);
+ w->has_data = 0;
+ mutex_unlock(&p->thread_lock);
+
+ wake_up(&p->wait);
+ } else {
+ p->thread_num--;
+ list_del(&w->worker_entry);
+ mutex_unlock(&p->thread_lock);
+
+ thread_pool_exit_worker(w);
+ }
+}
+
+/*
+ * Thread action loop: waits until there is new work.
+ */
+static int thread_pool_worker_func(void *data)
+{
+ struct thread_pool_worker *w = data;
+
+ while (!kthread_should_stop()) {
+ wait_event_interruptible(w->wait,
+ kthread_should_stop() || w->has_data);
+
+ if (kthread_should_stop())
+ break;
+
+ if (!w->has_data)
+ continue;
+
+ w->action(w->private, w->schedule_data);
+ thread_pool_worker_make_ready(w);
+ }
+
+ return 0;
+}
+
+/*
+ * Remove single worker without specifying which one.
+ */
+void thread_pool_del_worker(struct thread_pool *p)
+{
+ struct thread_pool_worker *w = NULL;
+
+ while (!w) {
+ wait_event(p->wait, !list_empty(&p->ready_list) || !p->thread_num);
+
+ dprintk("%s: locking list_empty: %d, thread_num: %d.\n",
+ __func__, list_empty(&p->ready_list), p->thread_num);
+
+ mutex_lock(&p->thread_lock);
+ if (!list_empty(&p->ready_list)) {
+ w = list_first_entry(&p->ready_list,
+ struct thread_pool_worker,
+ worker_entry);
+
+ dprintk("%s: deleting w: %p, thread_num: %d, list: %p [%p.%p].\n",
+ __func__, w, p->thread_num, &p->ready_list,
+ p->ready_list.prev, p->ready_list.next);
+
+ p->thread_num--;
+ list_del(&w->worker_entry);
+ }
+ mutex_unlock(&p->thread_lock);
+ }
+
+ if (w)
+ thread_pool_exit_worker(w);
+ dprintk("%s: deleted w: %p, thread_num: %d.\n",
+ __func__, w, p->thread_num);
+}
+
+/*
+ * Remove a worker with given ID.
+ */
+void thread_pool_del_worker_id(struct thread_pool *p, unsigned int id)
+{
+ struct thread_pool_worker *w;
+ int found = 0;
+
+ mutex_lock(&p->thread_lock);
+ list_for_each_entry(w, &p->ready_list, worker_entry) {
+ if (w->id == id) {
+ found = 1;
+ p->thread_num--;
+ list_del(&w->worker_entry);
+ break;
+ }
+ }
+
+ if (!found) {
+ list_for_each_entry(w, &p->active_list, worker_entry) {
+ if (w->id == id) {
+ w->need_exit = 1;
+ break;
+ }
+ }
+ }
+ mutex_unlock(&p->thread_lock);
+
+ if (found)
+ thread_pool_exit_worker(w);
+}
+
+/*
+ * Add new worker thread with given parameters.
+ * If initialization callback fails, return error.
+ */
+int thread_pool_add_worker(struct thread_pool *p,
+ char *name,
+ unsigned int id,
+ void *(* init)(void *private),
+ void (* cleanup)(void *private),
+ void *private)
+{
+ struct thread_pool_worker *w;
+ int err = -ENOMEM;
+
+ w = kzalloc(sizeof(struct thread_pool_worker), GFP_KERNEL);
+ if (!w)
+ goto err_out_exit;
+
+ w->pool = p;
+ init_waitqueue_head(&w->wait);
+ w->cleanup = cleanup;
+ w->id = id;
+
+ w->thread = kthread_run(thread_pool_worker_func, w, "%s", name);
+ if (IS_ERR(w->thread)) {
+ err = PTR_ERR(w->thread);
+ goto err_out_free;
+ }
+
+ w->private = init(private);
+ if (IS_ERR(w->private)) {
+ err = PTR_ERR(w->private);
+ goto err_out_stop_thread;
+ }
+
+ mutex_lock(&p->thread_lock);
+ list_add_tail(&w->worker_entry, &p->ready_list);
+ p->thread_num++;
+ mutex_unlock(&p->thread_lock);
+
+ return 0;
+
+err_out_stop_thread:
+ kthread_stop(w->thread);
+err_out_free:
+ kfree(w);
+err_out_exit:
+ return err;
+}
+
+/*
+ * Destroy the whole pool.
+ */
+void thread_pool_destroy(struct thread_pool *p)
+{
+ while (p->thread_num) {
+ dprintk("%s: num: %d.\n", __func__, p->thread_num);
+ thread_pool_del_worker(p);
+ }
+
+ kfree(p);
+}
+
+/*
+ * Create a pool with given number of threads.
+ * They will have sequential IDs started from zero.
+ */
+struct thread_pool *thread_pool_create(int num, char *name,
+ void *(* init)(void *private),
+ void (* cleanup)(void *private),
+ void *private)
+{
+ struct thread_pool_worker *w, *tmp;
+ struct thread_pool *p;
+ int err = -ENOMEM;
+ int i;
+
+ p = kzalloc(sizeof(struct thread_pool), GFP_KERNEL);
+ if (!p)
+ goto err_out_exit;
+
+ init_waitqueue_head(&p->wait);
+ mutex_init(&p->thread_lock);
+ INIT_LIST_HEAD(&p->ready_list);
+ INIT_LIST_HEAD(&p->active_list);
+ p->thread_num = 0;
+
+ for (i=0; i<num; ++i) {
+ err = thread_pool_add_worker(p, name, i, init,
+ cleanup, private);
+ if (err)
+ goto err_out_free_all;
+ }
+
+ return p;
+
+err_out_free_all:
+ list_for_each_entry_safe(w, tmp, &p->ready_list, worker_entry) {
+ list_del(&w->worker_entry);
+ thread_pool_exit_worker(w);
+ }
+ kfree(p);
+err_out_exit:
+ return ERR_PTR(err);
+}
+
+/*
+ * Schedule execution of the action on a given thread,
+ * provided ID pointer has to match previously stored
+ * private data.
+ */
+int thread_pool_schedule_private(struct thread_pool *p,
+ int (* setup)(void *private, void *data),
+ int (* action)(void *private, void *data),
+ void *data, long timeout, void *id)
+{
+ struct thread_pool_worker *w, *tmp, *worker = NULL;
+ int err = 0;
+
+ while (!worker && !err) {
+ timeout = wait_event_interruptible_timeout(p->wait,
+ !list_empty(&p->ready_list),
+ timeout);
+
+ if (!timeout) {
+ err = -ETIMEDOUT;
+ break;
+ }
+
+ worker = NULL;
+ mutex_lock(&p->thread_lock);
+ list_for_each_entry_safe(w, tmp, &p->ready_list, worker_entry) {
+ if (id && id != w->private)
+ continue;
+
+ worker = w;
+
+ list_move_tail(&w->worker_entry, &p->active_list);
+
+ err = setup(w->private, data);
+ if (!err) {
+ w->schedule_data = data;
+ w->action = action;
+ w->has_data = 1;
+ wake_up(&w->wait);
+ } else {
+ list_move_tail(&w->worker_entry, &p->ready_list);
+ }
+
+ break;
+ }
+ mutex_unlock(&p->thread_lock);
+ }
+
+ return err;
+}
+
+/*
+ * Schedule execution on arbitrary thread from the pool.
+ */
+int thread_pool_schedule(struct thread_pool *p,
+ int (* setup)(void *private, void *data),
+ int (* action)(void *private, void *data),
+ void *data, long timeout)
+{
+ return thread_pool_schedule_private(p, setup,
+ action, data, timeout, NULL);
+}
diff --git a/drivers/staging/dst/trans.c b/drivers/staging/dst/trans.c
new file mode 100644
index 000000000000..557d372a496c
--- /dev/null
+++ b/drivers/staging/dst/trans.c
@@ -0,0 +1,335 @@
+/*
+ * 2007+ Copyright (c) Evgeniy Polyakov <zbr@ioremap.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.
+ */
+
+#include <linux/bio.h>
+#include <linux/dst.h>
+#include <linux/slab.h>
+#include <linux/mempool.h>
+
+/*
+ * Transaction memory pool size.
+ */
+static int dst_mempool_num = 32;
+module_param(dst_mempool_num, int, 0644);
+
+/*
+ * Transaction tree management.
+ */
+static inline int dst_trans_cmp(dst_gen_t gen, dst_gen_t new)
+{
+ if (gen < new)
+ return 1;
+ if (gen > new)
+ return -1;
+ return 0;
+}
+
+struct dst_trans *dst_trans_search(struct dst_node *node, dst_gen_t gen)
+{
+ struct rb_root *root = &node->trans_root;
+ struct rb_node *n = root->rb_node;
+ struct dst_trans *t, *ret = NULL;
+ int cmp;
+
+ while (n) {
+ t = rb_entry(n, struct dst_trans, trans_entry);
+
+ cmp = dst_trans_cmp(t->gen, gen);
+ if (cmp < 0)
+ n = n->rb_left;
+ else if (cmp > 0)
+ n = n->rb_right;
+ else {
+ ret = t;
+ break;
+ }
+ }
+
+ dprintk("%s: %s transaction: id: %llu.\n", __func__,
+ (ret)?"found":"not found", gen);
+
+ return ret;
+}
+
+static int dst_trans_insert(struct dst_trans *new)
+{
+ struct rb_root *root = &new->n->trans_root;
+ struct rb_node **n = &root->rb_node, *parent = NULL;
+ struct dst_trans *ret = NULL, *t;
+ int cmp;
+
+ while (*n) {
+ parent = *n;
+
+ t = rb_entry(parent, struct dst_trans, trans_entry);
+
+ cmp = dst_trans_cmp(t->gen, new->gen);
+ if (cmp < 0)
+ n = &parent->rb_left;
+ else if (cmp > 0)
+ n = &parent->rb_right;
+ else {
+ ret = t;
+ break;
+ }
+ }
+
+ new->send_time = jiffies;
+ if (ret) {
+ printk("%s: exist: old: gen: %llu, bio: %llu/%u, send_time: %lu, "
+ "new: gen: %llu, bio: %llu/%u, send_time: %lu.\n",
+ __func__,
+ ret->gen, (u64)ret->bio->bi_sector,
+ ret->bio->bi_size, ret->send_time,
+ new->gen, (u64)new->bio->bi_sector,
+ new->bio->bi_size, new->send_time);
+ return -EEXIST;
+ }
+
+ rb_link_node(&new->trans_entry, parent, n);
+ rb_insert_color(&new->trans_entry, root);
+
+ dprintk("%s: inserted: gen: %llu, bio: %llu/%u, send_time: %lu.\n",
+ __func__, new->gen, (u64)new->bio->bi_sector,
+ new->bio->bi_size, new->send_time);
+
+ return 0;
+}
+
+int dst_trans_remove_nolock(struct dst_trans *t)
+{
+ struct dst_node *n = t->n;
+
+ if (t->trans_entry.rb_parent_color) {
+ rb_erase(&t->trans_entry, &n->trans_root);
+ t->trans_entry.rb_parent_color = 0;
+ }
+ return 0;
+}
+
+int dst_trans_remove(struct dst_trans *t)
+{
+ int ret;
+ struct dst_node *n = t->n;
+
+ mutex_lock(&n->trans_lock);
+ ret = dst_trans_remove_nolock(t);
+ mutex_unlock(&n->trans_lock);
+
+ return ret;
+}
+
+/*
+ * When transaction is completed and there are no more users,
+ * we complete appriate block IO request with given error status.
+ */
+void dst_trans_put(struct dst_trans *t)
+{
+ if (atomic_dec_and_test(&t->refcnt)) {
+ struct bio *bio = t->bio;
+
+ dprintk("%s: completed t: %p, gen: %llu, bio: %p.\n",
+ __func__, t, t->gen, bio);
+
+ bio_endio(bio, t->error);
+ bio_put(bio);
+
+ dst_node_put(t->n);
+ mempool_free(t, t->n->trans_pool);
+ }
+}
+
+/*
+ * Process given block IO request: allocate transaction, insert it into the tree
+ * and send/schedule crypto processing.
+ */
+int dst_process_bio(struct dst_node *n, struct bio *bio)
+{
+ struct dst_trans *t;
+ int err = -ENOMEM;
+
+ t = mempool_alloc(n->trans_pool, GFP_NOFS);
+ if (!t)
+ goto err_out_exit;
+
+ t->n = dst_node_get(n);
+ t->bio = bio;
+ t->error = 0;
+ t->retries = 0;
+ atomic_set(&t->refcnt, 1);
+ t->gen = atomic_long_inc_return(&n->gen);
+
+ t->enc = bio_data_dir(bio);
+ dst_bio_to_cmd(bio, &t->cmd, DST_IO, t->gen);
+
+ mutex_lock(&n->trans_lock);
+ err = dst_trans_insert(t);
+ mutex_unlock(&n->trans_lock);
+ if (err)
+ goto err_out_free;
+
+ dprintk("%s: gen: %llu, bio: %llu/%u, dir/enc: %d, need_crypto: %d.\n",
+ __func__, t->gen, (u64)bio->bi_sector,
+ bio->bi_size, t->enc, dst_need_crypto(n));
+
+ if (dst_need_crypto(n) && t->enc)
+ dst_trans_crypto(t);
+ else
+ dst_trans_send(t);
+
+ return 0;
+
+err_out_free:
+ dst_node_put(n);
+ mempool_free(t, n->trans_pool);
+err_out_exit:
+ bio_endio(bio, err);
+ bio_put(bio);
+ return err;
+}
+
+/*
+ * Scan for timeout/stale transactions.
+ * Each transaction is being resent multiple times before error completion.
+ */
+static void dst_trans_scan(struct work_struct *work)
+{
+ struct dst_node *n = container_of(work, struct dst_node, trans_work.work);
+ struct rb_node *rb_node;
+ struct dst_trans *t;
+ unsigned long timeout = n->trans_scan_timeout;
+ int num = 10 * n->trans_max_retries;
+
+ mutex_lock(&n->trans_lock);
+
+ for (rb_node = rb_first(&n->trans_root); rb_node; ) {
+ t = rb_entry(rb_node, struct dst_trans, trans_entry);
+
+ if (timeout && time_after(t->send_time + timeout, jiffies)
+ && t->retries == 0)
+ break;
+#if 0
+ dprintk("%s: t: %p, gen: %llu, n: %s, retries: %u, max: %u.\n",
+ __func__, t, t->gen, n->name,
+ t->retries, n->trans_max_retries);
+#endif
+ if (--num == 0)
+ break;
+
+ dst_trans_get(t);
+
+ rb_node = rb_next(rb_node);
+
+ if (timeout && (++t->retries < n->trans_max_retries)) {
+ dst_trans_send(t);
+ } else {
+ t->error = -ETIMEDOUT;
+ dst_trans_remove_nolock(t);
+ dst_trans_put(t);
+ }
+
+ dst_trans_put(t);
+ }
+
+ mutex_unlock(&n->trans_lock);
+
+ /*
+ * If no timeout specified then system is in the middle of exiting process,
+ * so no need to reschedule scanning process again.
+ */
+ if (timeout) {
+ if (!num)
+ timeout = HZ;
+ schedule_delayed_work(&n->trans_work, timeout);
+ }
+}
+
+/*
+ * Flush all transactions and mark them as timed out.
+ * Destroy transaction pools.
+ */
+void dst_node_trans_exit(struct dst_node *n)
+{
+ struct dst_trans *t;
+ struct rb_node *rb_node;
+
+ if (!n->trans_cache)
+ return;
+
+ dprintk("%s: n: %p, cancelling the work.\n", __func__, n);
+ cancel_delayed_work_sync(&n->trans_work);
+ flush_scheduled_work();
+ dprintk("%s: n: %p, work has been cancelled.\n", __func__, n);
+
+ for (rb_node = rb_first(&n->trans_root); rb_node; ) {
+ t = rb_entry(rb_node, struct dst_trans, trans_entry);
+
+ dprintk("%s: t: %p, gen: %llu, n: %s.\n",
+ __func__, t, t->gen, n->name);
+
+ rb_node = rb_next(rb_node);
+
+ t->error = -ETIMEDOUT;
+ dst_trans_remove_nolock(t);
+ dst_trans_put(t);
+ }
+
+ mempool_destroy(n->trans_pool);
+ kmem_cache_destroy(n->trans_cache);
+}
+
+/*
+ * Initialize transaction storage for given node.
+ * Transaction stores not only control information,
+ * but also network command and crypto data (if needed)
+ * to reduce number of allocations. Thus transaction size
+ * differs from node to node.
+ */
+int dst_node_trans_init(struct dst_node *n, unsigned int size)
+{
+ /*
+ * We need this, since node with given name can be dropped from the
+ * hash table, but be still alive, so subsequent creation of the node
+ * with the same name may collide with existing cache name.
+ */
+
+ snprintf(n->cache_name, sizeof(n->cache_name), "%s-%p", n->name, n);
+
+ n->trans_cache = kmem_cache_create(n->cache_name,
+ size + n->crypto.crypto_attached_size,
+ 0, 0, NULL);
+ if (!n->trans_cache)
+ goto err_out_exit;
+
+ n->trans_pool = mempool_create_slab_pool(dst_mempool_num, n->trans_cache);
+ if (!n->trans_pool)
+ goto err_out_cache_destroy;
+
+ mutex_init(&n->trans_lock);
+ n->trans_root = RB_ROOT;
+
+ INIT_DELAYED_WORK(&n->trans_work, dst_trans_scan);
+ schedule_delayed_work(&n->trans_work, n->trans_scan_timeout);
+
+ dprintk("%s: n: %p, size: %u, crypto: %u.\n",
+ __func__, n, size, n->crypto.crypto_attached_size);
+
+ return 0;
+
+err_out_cache_destroy:
+ kmem_cache_destroy(n->trans_cache);
+err_out_exit:
+ return -ENOMEM;
+}
diff --git a/drivers/staging/meilhaus/Kconfig b/drivers/staging/meilhaus/Kconfig
index 6def83fa2c96..923af22a4686 100644
--- a/drivers/staging/meilhaus/Kconfig
+++ b/drivers/staging/meilhaus/Kconfig
@@ -4,6 +4,7 @@
menuconfig MEILHAUS
tristate "Meilhaus support"
+ depends on m
---help---
If you have a Meilhaus card, say Y (or M) here.
@@ -18,7 +19,7 @@ if MEILHAUS
config ME0600
tristate "Meilhaus ME-600 support"
default n
- depends on PCI
+ depends on PCI && m
help
This driver supports the Meilhaus ME-600 family of boards
that do data collection and multipurpose I/O.
@@ -29,7 +30,7 @@ config ME0600
config ME0900
tristate "Meilhaus ME-900 support"
default n
- depends on PCI
+ depends on PCI && m
help
This driver supports the Meilhaus ME-900 family of boards
that do data collection and multipurpose I/O.
@@ -40,7 +41,7 @@ config ME0900
config ME1000
tristate "Meilhaus ME-1000 support"
default n
- depends on PCI
+ depends on PCI && m
help
This driver supports the Meilhaus ME-1000 family of boards
that do data collection and multipurpose I/O.
@@ -51,7 +52,7 @@ config ME1000
config ME1400
tristate "Meilhaus ME-1400 support"
default n
- depends on PCI
+ depends on PCI && m
help
This driver supports the Meilhaus ME-1400 family of boards
that do data collection and multipurpose I/O.
@@ -62,7 +63,7 @@ config ME1400
config ME1600
tristate "Meilhaus ME-1600 support"
default n
- depends on PCI
+ depends on PCI && m
help
This driver supports the Meilhaus ME-1600 family of boards
that do data collection and multipurpose I/O.
@@ -73,7 +74,7 @@ config ME1600
config ME4600
tristate "Meilhaus ME-4600 support"
default n
- depends on PCI
+ depends on PCI && m
help
This driver supports the Meilhaus ME-4600 family of boards
that do data collection and multipurpose I/O.
@@ -84,7 +85,7 @@ config ME4600
config ME6000
tristate "Meilhaus ME-6000 support"
default n
- depends on PCI
+ depends on PCI && m
help
This driver supports the Meilhaus ME-6000 family of boards
that do data collection and multipurpose I/O.
@@ -95,7 +96,7 @@ config ME6000
config ME8100
tristate "Meilhaus ME-8100 support"
default n
- depends on PCI
+ depends on PCI && m
help
This driver supports the Meilhaus ME-8100 family of boards
that do data collection and multipurpose I/O.
@@ -106,7 +107,7 @@ config ME8100
config ME8200
tristate "Meilhaus ME-8200 support"
default n
- depends on PCI
+ depends on PCI && m
help
This driver supports the Meilhaus ME-8200 family of boards
that do data collection and multipurpose I/O.
@@ -117,7 +118,7 @@ config ME8200
config MEDUMMY
tristate "Meilhaus dummy driver"
default n
- depends on PCI
+ depends on PCI && m
help
This provides a dummy driver for the Meilhaus driver package
diff --git a/drivers/staging/stlc45xx/Kconfig b/drivers/staging/stlc45xx/Kconfig
new file mode 100644
index 000000000000..8d3f46f190e8
--- /dev/null
+++ b/drivers/staging/stlc45xx/Kconfig
@@ -0,0 +1,8 @@
+config STLC45XX
+ tristate "stlc4550/4560 support"
+ depends on MAC80211 && WLAN_80211 && SPI_MASTER
+ ---help---
+ This is a driver for stlc4550 and stlc4560 chipsets.
+
+ To compile this driver as a module, choose M here: the module will be
+ called stlc45xx. If unsure, say N.
diff --git a/drivers/staging/stlc45xx/Makefile b/drivers/staging/stlc45xx/Makefile
new file mode 100644
index 000000000000..7ee32903055a
--- /dev/null
+++ b/drivers/staging/stlc45xx/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_STLC45XX) += stlc45xx.o
diff --git a/drivers/staging/stlc45xx/stlc45xx.c b/drivers/staging/stlc45xx/stlc45xx.c
new file mode 100644
index 000000000000..1defbb50219e
--- /dev/null
+++ b/drivers/staging/stlc45xx/stlc45xx.c
@@ -0,0 +1,2606 @@
+/*
+ * This file is part of stlc45xx
+ *
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * Contact: Kalle Valo <kalle.valo@nokia.com>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include "stlc45xx.h"
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/firmware.h>
+#include <linux/delay.h>
+#include <linux/irq.h>
+#include <linux/spi/spi.h>
+#include <linux/etherdevice.h>
+#include <linux/gpio.h>
+#include <linux/moduleparam.h>
+
+#include "stlc45xx_lmac.h"
+
+/*
+ * gpios should be handled in board files and provided via platform data,
+ * but because it's currently impossible for stlc45xx to have a header file
+ * in include/linux, let's use module paramaters for now
+ */
+static int stlc45xx_gpio_power = 97;
+module_param(stlc45xx_gpio_power, int, 0444);
+MODULE_PARM_DESC(stlc45xx_gpio_power, "stlc45xx gpio number for power line");
+
+static int stlc45xx_gpio_irq = 87;
+module_param(stlc45xx_gpio_irq, int, 0444);
+MODULE_PARM_DESC(stlc45xx_gpio_irq, "stlc45xx gpio number for irq line");
+
+static const u8 default_cal_channels[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x09,
+ 0x00, 0x00, 0xc9, 0xff, 0xd8, 0xff, 0x00, 0x00, 0x00, 0x01, 0x10,
+ 0x01, 0x10, 0x01, 0x10, 0x01, 0x10, 0x01, 0xe0, 0x00, 0xe0, 0x00,
+ 0xe0, 0x00, 0xe0, 0x00, 0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00, 0xd0,
+ 0x00, 0x54, 0x01, 0xab, 0xf6, 0xc0, 0x42, 0xc0, 0x42, 0xc0, 0x42,
+ 0xc0, 0x42, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00,
+ 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x22, 0x01, 0x37, 0xa9,
+ 0xc0, 0x33, 0xc0, 0x33, 0xc0, 0x33, 0xc0, 0x33, 0x00, 0xbc, 0x00,
+ 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc,
+ 0x00, 0xbc, 0xfb, 0x00, 0xca, 0x79, 0xc0, 0x2b, 0xc0, 0x2b, 0xc0,
+ 0x2b, 0xc0, 0x2b, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4,
+ 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0xd0, 0x00, 0x5d,
+ 0x54, 0xc0, 0x21, 0xc0, 0x21, 0xc0, 0x21, 0xc0, 0x21, 0x00, 0xaa,
+ 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00,
+ 0xaa, 0x00, 0xaa, 0xa7, 0x00, 0xa9, 0x3d, 0xc0, 0x17, 0xc0, 0x17,
+ 0xc0, 0x17, 0xc0, 0x17, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00,
+ 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x7a, 0x00,
+ 0x06, 0x2c, 0xc0, 0x0d, 0xc0, 0x0d, 0xc0, 0x0d, 0xc0, 0x0d, 0x00,
+ 0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96,
+ 0x00, 0x96, 0x00, 0x96, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x06, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x71, 0x09, 0x00, 0x00, 0xc9, 0xff, 0xd8,
+ 0xff, 0x00, 0x00, 0x00, 0x01, 0x10, 0x01, 0x10, 0x01, 0x10, 0x01,
+ 0x10, 0x01, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xd0,
+ 0x00, 0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00, 0x54, 0x01, 0xab, 0xf6,
+ 0xc0, 0x42, 0xc0, 0x42, 0xc0, 0x42, 0xc0, 0x42, 0x00, 0xcb, 0x00,
+ 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb,
+ 0x00, 0xcb, 0x22, 0x01, 0x37, 0xa9, 0xc0, 0x33, 0xc0, 0x33, 0xc0,
+ 0x33, 0xc0, 0x33, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc,
+ 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0xfb, 0x00, 0xca,
+ 0x79, 0xc0, 0x2b, 0xc0, 0x2b, 0xc0, 0x2b, 0xc0, 0x2b, 0x00, 0xb4,
+ 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00,
+ 0xb4, 0x00, 0xb4, 0xd0, 0x00, 0x5d, 0x54, 0xc0, 0x21, 0xc0, 0x21,
+ 0xc0, 0x21, 0xc0, 0x21, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00,
+ 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0xa7, 0x00,
+ 0xa9, 0x3d, 0xc0, 0x17, 0xc0, 0x17, 0xc0, 0x17, 0xc0, 0x17, 0x00,
+ 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0,
+ 0x00, 0xa0, 0x00, 0xa0, 0x7a, 0x00, 0x06, 0x2c, 0xc0, 0x0d, 0xc0,
+ 0x0d, 0xc0, 0x0d, 0xc0, 0x0d, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96,
+ 0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x80, 0x80,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76,
+ 0x09, 0x00, 0x00, 0xc9, 0xff, 0xd8, 0xff, 0x00, 0x00, 0x00, 0x01,
+ 0x10, 0x01, 0x10, 0x01, 0x10, 0x01, 0x10, 0x01, 0xf0, 0x00, 0xf0,
+ 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00,
+ 0xd0, 0x00, 0x54, 0x01, 0xab, 0xf6, 0xc0, 0x42, 0xc0, 0x42, 0xc0,
+ 0x42, 0xc0, 0x42, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb,
+ 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x22, 0x01, 0x37,
+ 0xa9, 0xc0, 0x33, 0xc0, 0x33, 0xc0, 0x33, 0xc0, 0x33, 0x00, 0xbc,
+ 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00,
+ 0xbc, 0x00, 0xbc, 0xfb, 0x00, 0xca, 0x79, 0xc0, 0x2b, 0xc0, 0x2b,
+ 0xc0, 0x2b, 0xc0, 0x2b, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00,
+ 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0xd0, 0x00,
+ 0x5d, 0x54, 0xc0, 0x21, 0xc0, 0x21, 0xc0, 0x21, 0xc0, 0x21, 0x00,
+ 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa,
+ 0x00, 0xaa, 0x00, 0xaa, 0xa7, 0x00, 0xa9, 0x3d, 0xc0, 0x17, 0xc0,
+ 0x17, 0xc0, 0x17, 0xc0, 0x17, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0,
+ 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x7a,
+ 0x00, 0x06, 0x2c, 0xc0, 0x0d, 0xc0, 0x0d, 0xc0, 0x0d, 0xc0, 0x0d,
+ 0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00,
+ 0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x06, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7b, 0x09, 0x00, 0x00, 0xc9, 0xff,
+ 0xd8, 0xff, 0x00, 0x00, 0x00, 0x01, 0x10, 0x01, 0x10, 0x01, 0x10,
+ 0x01, 0x10, 0x01, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00,
+ 0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00, 0x54, 0x01, 0xab,
+ 0xf6, 0xc0, 0x42, 0xc0, 0x42, 0xc0, 0x42, 0xc0, 0x42, 0x00, 0xcb,
+ 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00,
+ 0xcb, 0x00, 0xcb, 0x22, 0x01, 0x37, 0xa9, 0xc0, 0x33, 0xc0, 0x33,
+ 0xc0, 0x33, 0xc0, 0x33, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00,
+ 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0xfb, 0x00,
+ 0xca, 0x79, 0xc0, 0x2b, 0xc0, 0x2b, 0xc0, 0x2b, 0xc0, 0x2b, 0x00,
+ 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4,
+ 0x00, 0xb4, 0x00, 0xb4, 0xd0, 0x00, 0x5d, 0x54, 0xc0, 0x21, 0xc0,
+ 0x21, 0xc0, 0x21, 0xc0, 0x21, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa,
+ 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0xa7,
+ 0x00, 0xa9, 0x3d, 0xc0, 0x17, 0xc0, 0x17, 0xc0, 0x17, 0xc0, 0x17,
+ 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00,
+ 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x7a, 0x00, 0x06, 0x2c, 0xc0, 0x0d,
+ 0xc0, 0x0d, 0xc0, 0x0d, 0xc0, 0x0d, 0x00, 0x96, 0x00, 0x96, 0x00,
+ 0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x80,
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x09, 0x00, 0x00, 0xc9, 0xff, 0xd8, 0xff, 0x00, 0x00, 0x00,
+ 0x01, 0x10, 0x01, 0x10, 0x01, 0x10, 0x01, 0x10, 0x01, 0xf0, 0x00,
+ 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xd0, 0x00, 0xd0, 0x00, 0xd0,
+ 0x00, 0xd0, 0x00, 0x54, 0x01, 0xab, 0xf6, 0xc0, 0x42, 0xc0, 0x42,
+ 0xc0, 0x42, 0xc0, 0x42, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00,
+ 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x22, 0x01,
+ 0x37, 0xa9, 0xc0, 0x33, 0xc0, 0x33, 0xc0, 0x33, 0xc0, 0x33, 0x00,
+ 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc,
+ 0x00, 0xbc, 0x00, 0xbc, 0xfb, 0x00, 0xca, 0x79, 0xc0, 0x2b, 0xc0,
+ 0x2b, 0xc0, 0x2b, 0xc0, 0x2b, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4,
+ 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0xd0,
+ 0x00, 0x5d, 0x54, 0xc0, 0x21, 0xc0, 0x21, 0xc0, 0x21, 0xc0, 0x21,
+ 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00,
+ 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0xa7, 0x00, 0xa9, 0x3d, 0xc0, 0x17,
+ 0xc0, 0x17, 0xc0, 0x17, 0xc0, 0x17, 0x00, 0xa0, 0x00, 0xa0, 0x00,
+ 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0,
+ 0x7a, 0x00, 0x06, 0x2c, 0xc0, 0x0d, 0xc0, 0x0d, 0xc0, 0x0d, 0xc0,
+ 0x0d, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96,
+ 0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x06, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x85, 0x09, 0x00, 0x00, 0xc9,
+ 0xff, 0xd8, 0xff, 0x00, 0x00, 0x00, 0x01, 0x10, 0x01, 0x10, 0x01,
+ 0x10, 0x01, 0x10, 0x01, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0,
+ 0x00, 0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00, 0x54, 0x01,
+ 0xab, 0xf6, 0xc0, 0x42, 0xc0, 0x42, 0xc0, 0x42, 0xc0, 0x42, 0x00,
+ 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb,
+ 0x00, 0xcb, 0x00, 0xcb, 0x22, 0x01, 0x37, 0xa9, 0xc0, 0x33, 0xc0,
+ 0x33, 0xc0, 0x33, 0xc0, 0x33, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc,
+ 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0xfb,
+ 0x00, 0xca, 0x79, 0xc0, 0x2b, 0xc0, 0x2b, 0xc0, 0x2b, 0xc0, 0x2b,
+ 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00,
+ 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0xd0, 0x00, 0x5d, 0x54, 0xc0, 0x21,
+ 0xc0, 0x21, 0xc0, 0x21, 0xc0, 0x21, 0x00, 0xaa, 0x00, 0xaa, 0x00,
+ 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa,
+ 0xa7, 0x00, 0xa9, 0x3d, 0xc0, 0x17, 0xc0, 0x17, 0xc0, 0x17, 0xc0,
+ 0x17, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0,
+ 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x7a, 0x00, 0x06, 0x2c, 0xc0,
+ 0x0d, 0xc0, 0x0d, 0xc0, 0x0d, 0xc0, 0x0d, 0x00, 0x96, 0x00, 0x96,
+ 0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00,
+ 0x96, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06,
+ 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x8a, 0x09, 0x00, 0x00, 0xc9, 0xff, 0xd8, 0xff, 0x00, 0x00,
+ 0x00, 0x01, 0x10, 0x01, 0x10, 0x01, 0x10, 0x01, 0x10, 0x01, 0xf0,
+ 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xd0, 0x00, 0xd0, 0x00,
+ 0xd0, 0x00, 0xd0, 0x00, 0x54, 0x01, 0xab, 0xf6, 0xc0, 0x42, 0xc0,
+ 0x42, 0xc0, 0x42, 0xc0, 0x42, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb,
+ 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x22,
+ 0x01, 0x37, 0xa9, 0xc0, 0x33, 0xc0, 0x33, 0xc0, 0x33, 0xc0, 0x33,
+ 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00,
+ 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0xfb, 0x00, 0xca, 0x79, 0xc0, 0x2b,
+ 0xc0, 0x2b, 0xc0, 0x2b, 0xc0, 0x2b, 0x00, 0xb4, 0x00, 0xb4, 0x00,
+ 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4,
+ 0xd0, 0x00, 0x5d, 0x54, 0xc0, 0x21, 0xc0, 0x21, 0xc0, 0x21, 0xc0,
+ 0x21, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa,
+ 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0xa7, 0x00, 0xa9, 0x3d, 0xc0,
+ 0x17, 0xc0, 0x17, 0xc0, 0x17, 0xc0, 0x17, 0x00, 0xa0, 0x00, 0xa0,
+ 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00,
+ 0xa0, 0x7a, 0x00, 0x06, 0x2c, 0xc0, 0x0d, 0xc0, 0x0d, 0xc0, 0x0d,
+ 0xc0, 0x0d, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00,
+ 0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x80, 0x80, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8f, 0x09, 0x00, 0x00,
+ 0xc9, 0xff, 0xd8, 0xff, 0x00, 0x00, 0x00, 0x01, 0x10, 0x01, 0x10,
+ 0x01, 0x10, 0x01, 0x10, 0x01, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00,
+ 0xf0, 0x00, 0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00, 0x54,
+ 0x01, 0xab, 0xf6, 0xc0, 0x42, 0xc0, 0x42, 0xc0, 0x42, 0xc0, 0x42,
+ 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00,
+ 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x22, 0x01, 0x37, 0xa9, 0xc0, 0x33,
+ 0xc0, 0x33, 0xc0, 0x33, 0xc0, 0x33, 0x00, 0xbc, 0x00, 0xbc, 0x00,
+ 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc,
+ 0xfb, 0x00, 0xca, 0x79, 0xc0, 0x2b, 0xc0, 0x2b, 0xc0, 0x2b, 0xc0,
+ 0x2b, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4,
+ 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0xd0, 0x00, 0x5d, 0x54, 0xc0,
+ 0x21, 0xc0, 0x21, 0xc0, 0x21, 0xc0, 0x21, 0x00, 0xaa, 0x00, 0xaa,
+ 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00,
+ 0xaa, 0xa7, 0x00, 0xa9, 0x3d, 0xc0, 0x17, 0xc0, 0x17, 0xc0, 0x17,
+ 0xc0, 0x17, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00,
+ 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x7a, 0x00, 0x06, 0x2c,
+ 0xc0, 0x0d, 0xc0, 0x0d, 0xc0, 0x0d, 0xc0, 0x0d, 0x00, 0x96, 0x00,
+ 0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96,
+ 0x00, 0x96, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x06, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x94, 0x09, 0x00, 0x00, 0xc9, 0xff, 0xd8, 0xff, 0x00,
+ 0x00, 0x00, 0x01, 0x10, 0x01, 0x10, 0x01, 0x10, 0x01, 0x10, 0x01,
+ 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xd0, 0x00, 0xd0,
+ 0x00, 0xd0, 0x00, 0xd0, 0x00, 0x54, 0x01, 0xab, 0xf6, 0xc0, 0x42,
+ 0xc0, 0x42, 0xc0, 0x42, 0xc0, 0x42, 0x00, 0xcb, 0x00, 0xcb, 0x00,
+ 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb,
+ 0x22, 0x01, 0x37, 0xa9, 0xc0, 0x33, 0xc0, 0x33, 0xc0, 0x33, 0xc0,
+ 0x33, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc,
+ 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0xfb, 0x00, 0xca, 0x79, 0xc0,
+ 0x2b, 0xc0, 0x2b, 0xc0, 0x2b, 0xc0, 0x2b, 0x00, 0xb4, 0x00, 0xb4,
+ 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00,
+ 0xb4, 0xd0, 0x00, 0x5d, 0x54, 0xc0, 0x21, 0xc0, 0x21, 0xc0, 0x21,
+ 0xc0, 0x21, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00,
+ 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0xa7, 0x00, 0xa9, 0x3d,
+ 0xc0, 0x17, 0xc0, 0x17, 0xc0, 0x17, 0xc0, 0x17, 0x00, 0xa0, 0x00,
+ 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0,
+ 0x00, 0xa0, 0x7a, 0x00, 0x06, 0x2c, 0xc0, 0x0d, 0xc0, 0x0d, 0xc0,
+ 0x0d, 0xc0, 0x0d, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96,
+ 0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x80, 0x80, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x09, 0x00,
+ 0x00, 0xc9, 0xff, 0xd8, 0xff, 0x00, 0x00, 0x00, 0x01, 0x10, 0x01,
+ 0x10, 0x01, 0x10, 0x01, 0x10, 0x01, 0xf0, 0x00, 0xf0, 0x00, 0xf0,
+ 0x00, 0xf0, 0x00, 0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00,
+ 0x54, 0x01, 0xab, 0xf6, 0xc0, 0x42, 0xc0, 0x42, 0xc0, 0x42, 0xc0,
+ 0x42, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb,
+ 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x22, 0x01, 0x37, 0xa9, 0xc0,
+ 0x33, 0xc0, 0x33, 0xc0, 0x33, 0xc0, 0x33, 0x00, 0xbc, 0x00, 0xbc,
+ 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00,
+ 0xbc, 0xfb, 0x00, 0xca, 0x79, 0xc0, 0x2b, 0xc0, 0x2b, 0xc0, 0x2b,
+ 0xc0, 0x2b, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00,
+ 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0xd0, 0x00, 0x5d, 0x54,
+ 0xc0, 0x21, 0xc0, 0x21, 0xc0, 0x21, 0xc0, 0x21, 0x00, 0xaa, 0x00,
+ 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa,
+ 0x00, 0xaa, 0xa7, 0x00, 0xa9, 0x3d, 0xc0, 0x17, 0xc0, 0x17, 0xc0,
+ 0x17, 0xc0, 0x17, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0,
+ 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x7a, 0x00, 0x06,
+ 0x2c, 0xc0, 0x0d, 0xc0, 0x0d, 0xc0, 0x0d, 0xc0, 0x0d, 0x00, 0x96,
+ 0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00,
+ 0x96, 0x00, 0x96, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x06, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x9e, 0x09, 0x00, 0x00, 0xc9, 0xff, 0xd8, 0xff,
+ 0x00, 0x00, 0x00, 0x01, 0x10, 0x01, 0x10, 0x01, 0x10, 0x01, 0x10,
+ 0x01, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xd0, 0x00,
+ 0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00, 0x54, 0x01, 0xab, 0xf6, 0xc0,
+ 0x42, 0xc0, 0x42, 0xc0, 0x42, 0xc0, 0x42, 0x00, 0xcb, 0x00, 0xcb,
+ 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00,
+ 0xcb, 0x22, 0x01, 0x37, 0xa9, 0xc0, 0x33, 0xc0, 0x33, 0xc0, 0x33,
+ 0xc0, 0x33, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00,
+ 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0xfb, 0x00, 0xca, 0x79,
+ 0xc0, 0x2b, 0xc0, 0x2b, 0xc0, 0x2b, 0xc0, 0x2b, 0x00, 0xb4, 0x00,
+ 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4,
+ 0x00, 0xb4, 0xd0, 0x00, 0x5d, 0x54, 0xc0, 0x21, 0xc0, 0x21, 0xc0,
+ 0x21, 0xc0, 0x21, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa,
+ 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0xa7, 0x00, 0xa9,
+ 0x3d, 0xc0, 0x17, 0xc0, 0x17, 0xc0, 0x17, 0xc0, 0x17, 0x00, 0xa0,
+ 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00,
+ 0xa0, 0x00, 0xa0, 0x7a, 0x00, 0x06, 0x2c, 0xc0, 0x0d, 0xc0, 0x0d,
+ 0xc0, 0x0d, 0xc0, 0x0d, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00,
+ 0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x80, 0x80, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00 };
+
+static const u8 default_cal_rssi[] = {
+ 0x0a, 0x01, 0x72, 0xfe, 0x1a, 0x00, 0x00, 0x00, 0x0a, 0x01, 0x72,
+ 0xfe, 0x1a, 0x00, 0x00, 0x00, 0x0a, 0x01, 0x72, 0xfe, 0x1a, 0x00,
+ 0x00, 0x00, 0x0a, 0x01, 0x72, 0xfe, 0x1a, 0x00, 0x00, 0x00, 0x0a,
+ 0x01, 0x72, 0xfe, 0x1a, 0x00, 0x00, 0x00, 0x0a, 0x01, 0x72, 0xfe,
+ 0x1a, 0x00, 0x00, 0x00, 0x0a, 0x01, 0x72, 0xfe, 0x1a, 0x00, 0x00,
+ 0x00, 0x0a, 0x01, 0x72, 0xfe, 0x1a, 0x00, 0x00, 0x00, 0x0a, 0x01,
+ 0x72, 0xfe, 0x1a, 0x00, 0x00, 0x00, 0x0a, 0x01, 0x72, 0xfe, 0x1a,
+ 0x00, 0x00, 0x00, 0x0a, 0x01, 0x72, 0xfe, 0x1a, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+static void stlc45xx_tx_edcf(struct stlc45xx *stlc);
+static void stlc45xx_tx_setup(struct stlc45xx *stlc);
+static void stlc45xx_tx_scan(struct stlc45xx *stlc);
+static void stlc45xx_tx_psm(struct stlc45xx *stlc, bool enable);
+static int stlc45xx_tx_nullfunc(struct stlc45xx *stlc, bool powersave);
+static int stlc45xx_tx_pspoll(struct stlc45xx *stlc, bool powersave);
+
+static ssize_t stlc45xx_sysfs_show_cal_rssi(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct stlc45xx *stlc = dev_get_drvdata(dev);
+ ssize_t len;
+
+ stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
+
+ len = PAGE_SIZE;
+
+ mutex_lock(&stlc->mutex);
+
+ if (stlc->cal_rssi)
+ hex_dump_to_buffer(stlc->cal_rssi, RSSI_CAL_ARRAY_LEN, 16,
+ 2, buf, len, 0);
+ mutex_unlock(&stlc->mutex);
+
+ len = strlen(buf);
+
+ return len;
+}
+
+static ssize_t stlc45xx_sysfs_store_cal_rssi(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct stlc45xx *stlc = dev_get_drvdata(dev);
+
+ stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
+
+ mutex_lock(&stlc->mutex);
+
+ if (count != RSSI_CAL_ARRAY_LEN) {
+ stlc45xx_error("invalid cal_rssi length: %d", count);
+ count = 0;
+ goto out_unlock;
+ }
+
+ kfree(stlc->cal_rssi);
+
+ stlc->cal_rssi = kmemdup(buf, RSSI_CAL_ARRAY_LEN, GFP_KERNEL);
+
+ if (!stlc->cal_rssi) {
+ stlc45xx_error("failed to allocate memory for cal_rssi");
+ count = 0;
+ goto out_unlock;
+ }
+
+ out_unlock:
+ mutex_unlock(&stlc->mutex);
+
+ return count;
+}
+
+static ssize_t stlc45xx_sysfs_show_cal_channels(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct stlc45xx *stlc = dev_get_drvdata(dev);
+ ssize_t len;
+
+ stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
+
+ len = PAGE_SIZE;
+
+ mutex_lock(&stlc->mutex);
+
+ if (stlc->cal_channels)
+ hex_dump_to_buffer(stlc->cal_channels, CHANNEL_CAL_ARRAY_LEN,
+ 16, 2, buf, len, 0);
+
+ mutex_unlock(&stlc->mutex);
+
+ len = strlen(buf);
+
+ return len;
+}
+
+static ssize_t stlc45xx_sysfs_store_cal_channels(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct stlc45xx *stlc = dev_get_drvdata(dev);
+
+ stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
+
+ mutex_lock(&stlc->mutex);
+
+ if (count != CHANNEL_CAL_ARRAY_LEN) {
+ stlc45xx_error("invalid cal_channels size: %d ", count);
+ count = 0;
+ goto out_unlock;
+ }
+
+ kfree(stlc->cal_channels);
+
+ stlc->cal_channels = kmemdup(buf, count, GFP_KERNEL);
+
+ if (!stlc->cal_channels) {
+ stlc45xx_error("failed to allocate memory for cal_channels");
+ count = 0;
+ goto out_unlock;
+ }
+
+out_unlock:
+ mutex_unlock(&stlc->mutex);
+
+ return count;
+}
+
+static ssize_t stlc45xx_sysfs_show_tx_buf(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct stlc45xx *stlc = dev_get_drvdata(dev);
+ struct txbuffer *entry;
+ ssize_t len = 0;
+
+ stlc45xx_debug(DEBUG_FUNC, "%s()", __func__);
+
+ mutex_lock(&stlc->mutex);
+
+ list_for_each_entry(entry, &stlc->tx_sent, tx_list) {
+ len += sprintf(buf + len, "0x%x: 0x%x-0x%x\n",
+ entry->handle, entry->start,
+ entry->end);
+ }
+
+ mutex_unlock(&stlc->mutex);
+
+ return len;
+}
+
+static DEVICE_ATTR(cal_rssi, S_IRUGO | S_IWUSR,
+ stlc45xx_sysfs_show_cal_rssi,
+ stlc45xx_sysfs_store_cal_rssi);
+static DEVICE_ATTR(cal_channels, S_IRUGO | S_IWUSR,
+ stlc45xx_sysfs_show_cal_channels,
+ stlc45xx_sysfs_store_cal_channels);
+static DEVICE_ATTR(tx_buf, S_IRUGO, stlc45xx_sysfs_show_tx_buf, NULL);
+
+static void stlc45xx_spi_read(struct stlc45xx *stlc, unsigned long addr,
+ void *buf, size_t len)
+{
+ struct spi_transfer t[2];
+ struct spi_message m;
+
+ /* We first push the address */
+ addr = (addr << 8) | ADDR_READ_BIT_15;
+
+ spi_message_init(&m);
+ memset(t, 0, sizeof(t));
+
+ t[0].tx_buf = &addr;
+ t[0].len = 2;
+ spi_message_add_tail(&t[0], &m);
+
+ t[1].rx_buf = buf;
+ t[1].len = len;
+ spi_message_add_tail(&t[1], &m);
+
+ spi_sync(stlc->spi, &m);
+}
+
+
+static void stlc45xx_spi_write(struct stlc45xx *stlc, unsigned long addr,
+ void *buf, size_t len)
+{
+ struct spi_transfer t[3];
+ struct spi_message m;
+ u16 last_word;
+
+ /* We first push the address */
+ addr = addr << 8;
+
+ spi_message_init(&m);
+ memset(t, 0, sizeof(t));
+
+ t[0].tx_buf = &addr;
+ t[0].len = 2;
+ spi_message_add_tail(&t[0], &m);
+
+ t[1].tx_buf = buf;
+ t[1].len = len;
+ spi_message_add_tail(&t[1], &m);
+
+ if (len % 2) {
+ last_word = ((u8 *)buf)[len - 1];
+
+ t[2].tx_buf = &last_word;
+ t[2].len = 2;
+ spi_message_add_tail(&t[2], &m);
+ }
+
+ spi_sync(stlc->spi, &m);
+}
+
+static u16 stlc45xx_read16(struct stlc45xx *stlc, unsigned long addr)
+{
+ u16 val;
+
+ stlc45xx_spi_read(stlc, addr, &val, sizeof(val));
+
+ return val;
+}
+
+static u32 stlc45xx_read32(struct stlc45xx *stlc, unsigned long addr)
+{
+ u32 val;
+
+ stlc45xx_spi_read(stlc, addr, &val, sizeof(val));
+
+ return val;
+}
+
+static void stlc45xx_write16(struct stlc45xx *stlc, unsigned long addr, u16 val)
+{
+ stlc45xx_spi_write(stlc, addr, &val, sizeof(val));
+}
+
+static void stlc45xx_write32(struct stlc45xx *stlc, unsigned long addr, u32 val)
+{
+ stlc45xx_spi_write(stlc, addr, &val, sizeof(val));
+}
+
+struct stlc45xx_spi_reg {
+ u16 address;
+ u16 length;
+ char *name;
+};
+
+/* caller must hold tx_lock */
+static void stlc45xx_txbuffer_dump(struct stlc45xx *stlc)
+{
+ struct txbuffer *txbuffer;
+ char *buf, *pos;
+ int buf_len, l, count;
+
+ if (!(DEBUG_LEVEL & DEBUG_TXBUFFER))
+ return;
+
+ stlc45xx_debug(DEBUG_FUNC, "%s()", __func__);
+
+ buf_len = 500;
+ buf = kmalloc(buf_len, GFP_ATOMIC);
+ if (!buf)
+ return;
+
+ pos = buf;
+ count = 0;
+
+ list_for_each_entry(txbuffer, &stlc->txbuffer, buffer_list) {
+ l = snprintf(pos, buf_len, "0x%x-0x%x,",
+ txbuffer->start, txbuffer->end);
+ /* drop the null byte */
+ pos += l;
+ buf_len -= l;
+ count++;
+ }
+
+ if (count == 0)
+ *pos = '\0';
+ else
+ *--pos = '\0';
+
+ stlc45xx_debug(DEBUG_TXBUFFER, "txbuffer: in buffer %d regions: %s",
+ count, buf);
+
+ kfree(buf);
+}
+
+/* caller must hold tx_lock */
+static int stlc45xx_txbuffer_find(struct stlc45xx *stlc, size_t len)
+{
+ struct txbuffer *txbuffer;
+ int pos;
+
+ stlc45xx_debug(DEBUG_FUNC, "%s()", __func__);
+
+ pos = FIRMWARE_TXBUFFER_START;
+
+ if (list_empty(&stlc->txbuffer))
+ goto out;
+
+ /*
+ * the entries in txbuffer must be in the same order as they are in
+ * the real buffer
+ */
+ list_for_each_entry(txbuffer, &stlc->txbuffer, buffer_list) {
+ if (pos + len < txbuffer->start)
+ break;
+ pos = ALIGN(txbuffer->end + 1, 4);
+ }
+
+ if (pos + len > FIRMWARE_TXBUFFER_END)
+ /* not enough room */
+ pos = -1;
+
+ stlc45xx_debug(DEBUG_TXBUFFER, "txbuffer: find %d B: 0x%x", len, pos);
+
+out:
+ return pos;
+}
+
+static int stlc45xx_txbuffer_add(struct stlc45xx *stlc,
+ struct txbuffer *txbuffer)
+{
+ struct txbuffer *r, *prev = NULL;
+
+ if (list_empty(&stlc->txbuffer)) {
+ list_add(&txbuffer->buffer_list, &stlc->txbuffer);
+ return 0;
+ }
+
+ r = list_first_entry(&stlc->txbuffer, struct txbuffer, buffer_list);
+
+ if (txbuffer->start < r->start) {
+ /* add to the beginning of the list */
+ list_add(&txbuffer->buffer_list, &stlc->txbuffer);
+ return 0;
+ }
+
+ prev = NULL;
+ list_for_each_entry(r, &stlc->txbuffer, buffer_list) {
+ /* skip first entry, we checked for that above */
+ if (!prev) {
+ prev = r;
+ continue;
+ }
+
+ /* double-check overlaps */
+ WARN_ON_ONCE(txbuffer->start >= r->start &&
+ txbuffer->start <= r->end);
+ WARN_ON_ONCE(txbuffer->end >= r->start &&
+ txbuffer->end <= r->end);
+
+ if (prev->end < txbuffer->start &&
+ txbuffer->end < r->start) {
+ /* insert at this spot */
+ list_add_tail(&txbuffer->buffer_list, &r->buffer_list);
+ return 0;
+ }
+
+ prev = r;
+ }
+
+ /* not found */
+ list_add_tail(&txbuffer->buffer_list, &stlc->txbuffer);
+
+ return 0;
+
+}
+
+/* caller must hold tx_lock */
+static struct txbuffer *stlc45xx_txbuffer_alloc(struct stlc45xx *stlc,
+ size_t frame_len)
+{
+ struct txbuffer *entry = NULL;
+ size_t len;
+ int pos;
+
+ stlc45xx_debug(DEBUG_FUNC, "%s()", __func__);
+
+ len = FIRMWARE_TXBUFFER_HEADER + frame_len + FIRMWARE_TXBUFFER_TRAILER;
+ pos = stlc45xx_txbuffer_find(stlc, len);
+
+ if (pos < 0)
+ return NULL;
+
+ WARN_ON_ONCE(pos + len > FIRMWARE_TXBUFFER_END);
+ WARN_ON_ONCE(pos < FIRMWARE_TXBUFFER_START);
+
+ entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
+ entry->start = pos;
+ entry->frame_start = pos + FIRMWARE_TXBUFFER_HEADER;
+ entry->end = entry->start + len - 1;
+
+ stlc45xx_debug(DEBUG_TXBUFFER, "txbuffer: allocated 0x%x-0x%x",
+ entry->start, entry->end);
+
+ stlc45xx_txbuffer_add(stlc, entry);
+
+ stlc45xx_txbuffer_dump(stlc);
+
+ return entry;
+}
+
+/* caller must hold tx_lock */
+static void stlc45xx_txbuffer_free(struct stlc45xx *stlc,
+ struct txbuffer *txbuffer)
+{
+ stlc45xx_debug(DEBUG_FUNC, "%s()", __func__);
+
+ stlc45xx_debug(DEBUG_TXBUFFER, "txbuffer: freed 0x%x-0x%x",
+ txbuffer->start, txbuffer->end);
+
+ list_del(&txbuffer->buffer_list);
+ kfree(txbuffer);
+}
+
+
+static int stlc45xx_wait_bit(struct stlc45xx *stlc, u16 reg, u32 mask,
+ u32 expected)
+{
+ int i;
+ char buffer[4];
+
+ for (i = 0; i < 2000; i++) {
+ stlc45xx_spi_read(stlc, reg, buffer, sizeof(buffer));
+ if (((*(u32 *)buffer) & mask) == expected)
+ return 1;
+ msleep(1);
+ }
+
+ return 0;
+}
+
+static int stlc45xx_request_firmware(struct stlc45xx *stlc)
+{
+ const struct firmware *fw;
+ int ret;
+
+ /* FIXME: should driver use it's own struct device? */
+ ret = request_firmware(&fw, "3826.arm", &stlc->spi->dev);
+
+ if (ret < 0) {
+ stlc45xx_error("request_firmware() failed: %d", ret);
+ return ret;
+ }
+
+ if (fw->size % 4) {
+ stlc45xx_error("firmware size is not multiple of 32bit: %d",
+ fw->size);
+ return -EILSEQ; /* Illegal byte sequence */;
+ }
+
+ if (fw->size < 1000) {
+ stlc45xx_error("firmware is too small: %d", fw->size);
+ return -EILSEQ;
+ }
+
+ stlc->fw = kmemdup(fw->data, fw->size, GFP_KERNEL);
+ if (!stlc->fw) {
+ stlc45xx_error("could not allocate memory for firmware");
+ return -ENOMEM;
+ }
+
+ stlc->fw_len = fw->size;
+
+ release_firmware(fw);
+
+ return 0;
+}
+
+static int stlc45xx_upload_firmware(struct stlc45xx *stlc)
+{
+ struct s_dma_regs dma_regs;
+ unsigned long fw_len, fw_addr;
+ long _fw_len;
+ int ret;
+
+ stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
+
+ if (!stlc->fw) {
+ ret = stlc45xx_request_firmware(stlc);
+ if (ret < 0)
+ return ret;
+ }
+
+ /* stop the device */
+ stlc45xx_write16(stlc, SPI_ADRS_DEV_CTRL_STAT,
+ SPI_CTRL_STAT_HOST_OVERRIDE | SPI_CTRL_STAT_HOST_RESET
+ | SPI_CTRL_STAT_START_HALTED);
+
+ msleep(TARGET_BOOT_SLEEP);
+
+ stlc45xx_write16(stlc, SPI_ADRS_DEV_CTRL_STAT,
+ SPI_CTRL_STAT_HOST_OVERRIDE
+ | SPI_CTRL_STAT_START_HALTED);
+
+ msleep(TARGET_BOOT_SLEEP);
+
+ fw_addr = FIRMWARE_ADDRESS;
+ fw_len = stlc->fw_len;
+
+ while (fw_len > 0) {
+ _fw_len = (fw_len > SPI_MAX_PACKET_SIZE)
+ ? SPI_MAX_PACKET_SIZE : fw_len;
+ dma_regs.cmd = SPI_DMA_WRITE_CTRL_ENABLE;
+ dma_regs.len = cpu_to_le16(_fw_len);
+ dma_regs.addr = cpu_to_le32(fw_addr);
+
+ fw_len -= _fw_len;
+ fw_addr += _fw_len;
+
+ stlc45xx_write16(stlc, SPI_ADRS_DMA_WRITE_CTRL, dma_regs.cmd);
+
+ if (stlc45xx_wait_bit(stlc, SPI_ADRS_DMA_WRITE_CTRL,
+ HOST_ALLOWED, HOST_ALLOWED) == 0) {
+ stlc45xx_error("fw_upload not allowed to DMA write");
+ return -EAGAIN;
+ }
+
+ stlc45xx_write16(stlc, SPI_ADRS_DMA_WRITE_LEN, dma_regs.len);
+ stlc45xx_write32(stlc, SPI_ADRS_DMA_WRITE_BASE, dma_regs.addr);
+
+ stlc45xx_spi_write(stlc, SPI_ADRS_DMA_DATA, stlc->fw, _fw_len);
+
+ /* FIXME: I think this doesn't work if firmware is large,
+ * this loop goes to second round. fw->data is not
+ * increased at all! */
+ }
+
+ BUG_ON(fw_len != 0);
+
+ /* enable host interrupts */
+ stlc45xx_write32(stlc, SPI_ADRS_HOST_INT_EN, SPI_HOST_INTS_DEFAULT);
+
+ /* boot the device */
+ stlc45xx_write16(stlc, SPI_ADRS_DEV_CTRL_STAT,
+ SPI_CTRL_STAT_HOST_OVERRIDE | SPI_CTRL_STAT_HOST_RESET
+ | SPI_CTRL_STAT_RAM_BOOT);
+
+ msleep(TARGET_BOOT_SLEEP);
+
+ stlc45xx_write16(stlc, SPI_ADRS_DEV_CTRL_STAT,
+ SPI_CTRL_STAT_HOST_OVERRIDE | SPI_CTRL_STAT_RAM_BOOT);
+ msleep(TARGET_BOOT_SLEEP);
+
+ return 0;
+}
+
+/* caller must hold tx_lock */
+static void stlc45xx_check_txsent(struct stlc45xx *stlc)
+{
+ struct txbuffer *entry, *n;
+
+ list_for_each_entry_safe(entry, n, &stlc->tx_sent, tx_list) {
+ if (time_after(jiffies, entry->lifetime)) {
+ if (net_ratelimit())
+ stlc45xx_warning("frame 0x%x lifetime exceeded",
+ entry->start);
+ list_del(&entry->tx_list);
+ skb_pull(entry->skb, entry->header_len);
+ ieee80211_tx_status(stlc->hw, entry->skb);
+ stlc45xx_txbuffer_free(stlc, entry);
+ }
+ }
+}
+
+static void stlc45xx_power_off(struct stlc45xx *stlc)
+{
+ disable_irq(gpio_to_irq(stlc45xx_gpio_irq));
+ gpio_set_value(stlc45xx_gpio_power, 0);
+}
+
+static void stlc45xx_power_on(struct stlc45xx *stlc)
+{
+ gpio_set_value(stlc45xx_gpio_power, 1);
+ enable_irq(gpio_to_irq(stlc45xx_gpio_irq));
+
+ /*
+ * need to wait a while before device can be accessed, the length
+ * is just a guess
+ */
+ msleep(10);
+}
+
+/* caller must hold tx_lock */
+static void stlc45xx_flush_queues(struct stlc45xx *stlc)
+{
+ struct txbuffer *entry;
+
+ while (!list_empty(&stlc->tx_sent)) {
+ entry = list_first_entry(&stlc->tx_sent,
+ struct txbuffer, tx_list);
+ list_del(&entry->tx_list);
+ dev_kfree_skb(entry->skb);
+ stlc45xx_txbuffer_free(stlc, entry);
+ }
+
+ WARN_ON(!list_empty(&stlc->tx_sent));
+
+ while (!list_empty(&stlc->tx_pending)) {
+ entry = list_first_entry(&stlc->tx_pending,
+ struct txbuffer, tx_list);
+ list_del(&entry->tx_list);
+ dev_kfree_skb(entry->skb);
+ stlc45xx_txbuffer_free(stlc, entry);
+ }
+
+ WARN_ON(!list_empty(&stlc->tx_pending));
+ WARN_ON(!list_empty(&stlc->txbuffer));
+}
+
+static void stlc45xx_work_reset(struct work_struct *work)
+{
+ struct stlc45xx *stlc = container_of(work, struct stlc45xx,
+ work_reset);
+
+ mutex_lock(&stlc->mutex);
+
+ if (stlc->fw_state != FW_STATE_RESET)
+ goto out;
+
+ stlc45xx_power_off(stlc);
+
+ mutex_unlock(&stlc->mutex);
+
+ /* wait that all work_structs have finished, we can't hold
+ * stlc->mutex to avoid deadlock */
+ cancel_work_sync(&stlc->work);
+
+ /* FIXME: find out good value to wait for chip power down */
+ msleep(100);
+
+ mutex_lock(&stlc->mutex);
+
+ /* FIXME: we should gracefully handle if the state has changed
+ * after re-acquiring mutex */
+ WARN_ON(stlc->fw_state != FW_STATE_RESET);
+
+ spin_lock_bh(&stlc->tx_lock);
+ stlc45xx_flush_queues(stlc);
+ spin_unlock_bh(&stlc->tx_lock);
+
+ stlc->fw_state = FW_STATE_RESETTING;
+
+ stlc45xx_power_on(stlc);
+ stlc45xx_upload_firmware(stlc);
+
+out:
+ mutex_unlock(&stlc->mutex);
+}
+
+/* caller must hold mutex */
+static void stlc45xx_reset(struct stlc45xx *stlc)
+{
+ stlc45xx_warning("resetting firmware");
+ stlc->fw_state = FW_STATE_RESET;
+ ieee80211_stop_queues(stlc->hw);
+ queue_work(stlc->hw->workqueue, &stlc->work_reset);
+}
+
+static void stlc45xx_work_tx_timeout(struct work_struct *work)
+{
+ struct stlc45xx *stlc = container_of(work, struct stlc45xx,
+ work_tx_timeout.work);
+
+ stlc45xx_warning("tx timeout");
+
+ mutex_lock(&stlc->mutex);
+
+ if (stlc->fw_state != FW_STATE_READY)
+ goto out;
+
+ stlc45xx_reset(stlc);
+
+out:
+ mutex_unlock(&stlc->mutex);
+}
+
+static void stlc45xx_int_ack(struct stlc45xx *stlc, u32 val)
+{
+ stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
+
+ stlc45xx_write32(stlc, SPI_ADRS_HOST_INT_ACK, val);
+}
+
+static void stlc45xx_wakeup(struct stlc45xx *stlc)
+{
+ unsigned long timeout;
+ u32 ints;
+
+ stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
+
+ /* wake the chip */
+ stlc45xx_write32(stlc, SPI_ADRS_ARM_INTERRUPTS, SPI_TARGET_INT_WAKEUP);
+
+ /* And wait for the READY interrupt */
+ timeout = jiffies + HZ;
+
+ ints = stlc45xx_read32(stlc, SPI_ADRS_HOST_INTERRUPTS);
+ while (!(ints & SPI_HOST_INT_READY)) {
+ if (time_after(jiffies, timeout))
+ goto out;
+ ints = stlc45xx_read32(stlc, SPI_ADRS_HOST_INTERRUPTS);
+ }
+
+ stlc45xx_int_ack(stlc, SPI_HOST_INT_READY);
+
+out:
+ return;
+}
+
+static void stlc45xx_sleep(struct stlc45xx *stlc)
+{
+ stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
+
+ stlc45xx_write32(stlc, SPI_ADRS_ARM_INTERRUPTS, SPI_TARGET_INT_SLEEP);
+}
+
+static void stlc45xx_int_ready(struct stlc45xx *stlc)
+{
+ stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
+
+ stlc45xx_write32(stlc, SPI_ADRS_HOST_INT_EN,
+ SPI_HOST_INT_UPDATE | SPI_HOST_INT_SW_UPDATE);
+
+ switch (stlc->fw_state) {
+ case FW_STATE_BOOTING:
+ stlc->fw_state = FW_STATE_READY;
+ complete(&stlc->fw_comp);
+ break;
+ case FW_STATE_RESETTING:
+ stlc->fw_state = FW_STATE_READY;
+
+ stlc45xx_tx_scan(stlc);
+ stlc45xx_tx_setup(stlc);
+ stlc45xx_tx_edcf(stlc);
+
+ ieee80211_wake_queues(stlc->hw);
+ break;
+ default:
+ break;
+ }
+}
+
+static int stlc45xx_rx_txack(struct stlc45xx *stlc, struct sk_buff *skb)
+{
+ struct ieee80211_tx_info *info;
+ struct s_lm_control *control;
+ struct s_lmo_tx *tx;
+ struct txbuffer *entry;
+ int found = 0;
+
+ stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
+
+ control = (struct s_lm_control *) skb->data;
+ tx = (struct s_lmo_tx *) (control + 1);
+
+ if (list_empty(&stlc->tx_sent)) {
+ if (net_ratelimit())
+ stlc45xx_warning("no frames waiting for "
+ "acknowledgement");
+ return -1;
+ }
+
+ list_for_each_entry(entry, &stlc->tx_sent, tx_list) {
+ if (control->handle == entry->handle) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found) {
+ if (net_ratelimit())
+ stlc45xx_warning("couldn't find frame for tx ack 0x%x",
+ control->handle);
+ return -1;
+ }
+
+ stlc45xx_debug(DEBUG_TX, "TX ACK 0x%x", entry->handle);
+
+ if (entry->status_needed) {
+ info = IEEE80211_SKB_CB(entry->skb);
+
+ if (!(tx->flags & LM_TX_FAILED)) {
+ /* frame was acked */
+ info->flags |= IEEE80211_TX_STAT_ACK;
+ info->status.ack_signal = tx->rcpi / 2 - 110;
+ }
+
+ skb_pull(entry->skb, entry->header_len);
+
+ ieee80211_tx_status(stlc->hw, entry->skb);
+ }
+
+ list_del(&entry->tx_list);
+
+ stlc45xx_check_txsent(stlc);
+ if (list_empty(&stlc->tx_sent))
+ /* there are no pending frames, we can stop the tx timeout
+ * timer */
+ cancel_delayed_work(&stlc->work_tx_timeout);
+
+ spin_lock_bh(&stlc->tx_lock);
+
+ stlc45xx_txbuffer_free(stlc, entry);
+
+ if (stlc->tx_queue_stopped &&
+ stlc45xx_txbuffer_find(stlc, MAX_FRAME_LEN) != -1) {
+ stlc45xx_debug(DEBUG_QUEUE, "room in tx buffer, waking queues");
+ ieee80211_wake_queues(stlc->hw);
+ stlc->tx_queue_stopped = 0;
+ }
+
+ spin_unlock_bh(&stlc->tx_lock);
+
+ return 0;
+}
+
+static int stlc45xx_rx_control(struct stlc45xx *stlc, struct sk_buff *skb)
+{
+ struct s_lm_control *control;
+ int ret = 0;
+
+ stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
+
+ control = (struct s_lm_control *) skb->data;
+
+ switch (control->oid) {
+ case LM_OID_TX:
+ ret = stlc45xx_rx_txack(stlc, skb);
+ break;
+ case LM_OID_SETUP:
+ case LM_OID_SCAN:
+ case LM_OID_TRAP:
+ case LM_OID_EDCF:
+ case LM_OID_KEYCACHE:
+ case LM_OID_PSM:
+ case LM_OID_STATS:
+ case LM_OID_LED:
+ default:
+ stlc45xx_warning("unhandled rx control oid %d\n",
+ control->oid);
+ break;
+ }
+
+ dev_kfree_skb(skb);
+
+ return ret;
+}
+
+/* copied from mac80211 */
+static void stlc45xx_parse_elems(u8 *start, size_t len,
+ struct stlc45xx_ie_tim **tim,
+ size_t *tim_len)
+{
+ size_t left = len;
+ u8 *pos = start;
+
+ while (left >= 2) {
+ u8 id, elen;
+
+ id = *pos++;
+ elen = *pos++;
+ left -= 2;
+
+ if (elen > left)
+ return;
+
+ switch (id) {
+ case WLAN_EID_TIM:
+ *tim = (struct stlc45xx_ie_tim *) pos;
+ *tim_len = elen;
+ break;
+ default:
+ break;
+ }
+
+ left -= elen;
+ pos += elen;
+ }
+}
+
+/*
+ * mac80211 doesn't have support for asking frames with PS-Poll, so let's
+ * implement in the driver for now. We have to add support to mac80211
+ * later.
+ */
+static int stlc45xx_check_more_data(struct stlc45xx *stlc, struct sk_buff *skb)
+{
+ struct s_lm_data_in *data = (struct s_lm_data_in *) skb->data;
+ struct ieee80211_hdr *hdr;
+ size_t len;
+ u16 fc;
+
+ hdr = (void *) skb->data + sizeof(*data);
+ len = skb->len - sizeof(*data);
+
+ /* minimum frame length is the null frame length 24 bytes */
+ if (len < 24) {
+ stlc45xx_warning("invalid frame length when checking for "
+ "more data");
+ return -EINVAL;
+ }
+
+ fc = le16_to_cpu(hdr->frame_control);
+ if (!(fc & IEEE80211_FCTL_FROMDS))
+ /* this is not from DS */
+ return 0;
+
+ if (compare_ether_addr(hdr->addr1, stlc->mac_addr) != 0)
+ /* the frame was not for us */
+ return 0;
+
+ if (!(fc & IEEE80211_FCTL_MOREDATA)) {
+ /* AP has no more frames buffered for us */
+ stlc45xx_debug(DEBUG_PSM, "all buffered frames retrieved");
+ stlc->pspolling = false;
+ return 0;
+ }
+
+ /* MOREDATA bit is set, let's ask for a new frame from the AP */
+ stlc45xx_tx_pspoll(stlc, stlc->psm);
+
+ return 0;
+}
+
+/*
+ * mac80211 cannot read TIM from beacons, so let's add a hack to the
+ * driver. We have to add support to mac80211 later.
+ */
+static int stlc45xx_rx_data_beacon(struct stlc45xx *stlc, struct sk_buff *skb)
+{
+ struct s_lm_data_in *data = (struct s_lm_data_in *) skb->data;
+ size_t len = skb->len, tim_len = 0, baselen, pvbmap_len;
+ struct ieee80211_mgmt *mgmt;
+ struct stlc45xx_ie_tim *tim = NULL;
+ int bmap_offset, index, aid_bit;
+
+ mgmt = (void *) skb->data + sizeof(*data);
+
+ baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt;
+ if (baselen > len) {
+ stlc45xx_warning("invalid baselen in beacon");
+ return -EINVAL;
+ }
+
+ stlc45xx_parse_elems(mgmt->u.beacon.variable, len - baselen, &tim,
+ &tim_len);
+
+ if (!tim) {
+ stlc45xx_warning("didn't find tim from a beacon");
+ return -EINVAL;
+ }
+
+ bmap_offset = tim->bmap_control & 0xfe;
+ index = stlc->aid / 8 - bmap_offset;
+
+ pvbmap_len = tim_len - 3;
+ if (index > pvbmap_len)
+ return -EINVAL;
+
+ aid_bit = !!(tim->pvbmap[index] & (1 << stlc->aid % 8));
+
+ stlc45xx_debug(DEBUG_PSM, "fc 0x%x duration %d seq %d dtim %u "
+ "bmap_control 0x%x aid_bit %d",
+ mgmt->frame_control, mgmt->duration, mgmt->seq_ctrl >> 4,
+ tim->dtim_count, tim->bmap_control, aid_bit);
+
+ if (!aid_bit)
+ return 0;
+
+ stlc->pspolling = true;
+ stlc45xx_tx_pspoll(stlc, stlc->psm);
+
+ return 0;
+}
+
+static int stlc45xx_rx_data(struct stlc45xx *stlc, struct sk_buff *skb)
+{
+ struct ieee80211_rx_status status;
+ struct s_lm_data_in *data = (struct s_lm_data_in *) skb->data;
+ int align = 0;
+ u8 *p, align_len;
+ u16 len;
+
+ stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
+
+ if (stlc->psm) {
+ if (data->flags & LM_IN_BEACON)
+ stlc45xx_rx_data_beacon(stlc, skb);
+ else if (stlc->pspolling && (data->flags & LM_IN_DATA))
+ stlc45xx_check_more_data(stlc, skb);
+ }
+
+ memset(&status, 0, sizeof(status));
+
+ status.freq = data->frequency;
+ status.signal = data->rcpi / 2 - 110;
+
+ /* let's assume that maximum rcpi value is 140 (= 35 dBm) */
+ status.qual = data->rcpi * 100 / 140;
+
+ status.band = IEEE80211_BAND_2GHZ;
+
+ /*
+ * FIXME: this gives warning from __ieee80211_rx()
+ *
+ * status.rate_idx = data->rate;
+ */
+
+ len = data->length;
+
+ if (data->flags & LM_FLAG_ALIGN)
+ align = 1;
+
+ skb_pull(skb, sizeof(*data));
+
+ if (align) {
+ p = skb->data;
+ align_len = *p;
+ skb_pull(skb, align_len);
+ }
+
+ skb_trim(skb, len);
+
+ stlc45xx_debug(DEBUG_RX, "rx data 0x%p %d B", skb->data, skb->len);
+ stlc45xx_dump(DEBUG_RX_CONTENT, skb->data, skb->len);
+
+ ieee80211_rx(stlc->hw, skb, &status);
+
+ return 0;
+}
+
+
+
+static int stlc45xx_rx(struct stlc45xx *stlc)
+{
+ struct s_lm_control *control;
+ struct sk_buff *skb;
+ int ret;
+ u16 len;
+
+ stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
+
+ stlc45xx_wakeup(stlc);
+
+ /* dummy read to flush SPI DMA controller bug */
+ stlc45xx_read16(stlc, SPI_ADRS_GEN_PURP_1);
+
+ len = stlc45xx_read16(stlc, SPI_ADRS_DMA_DATA);
+
+ if (len == 0) {
+ stlc45xx_warning("rx request of zero bytes");
+ return 0;
+ }
+
+ skb = dev_alloc_skb(len);
+ if (!skb) {
+ stlc45xx_warning("could not alloc skb");
+ return 0;
+ }
+
+ stlc45xx_spi_read(stlc, SPI_ADRS_DMA_DATA, skb_put(skb, len), len);
+
+ stlc45xx_sleep(stlc);
+
+ stlc45xx_debug(DEBUG_RX, "rx frame 0x%p %d B", skb->data, skb->len);
+ stlc45xx_dump(DEBUG_RX_CONTENT, skb->data, skb->len);
+
+ control = (struct s_lm_control *) skb->data;
+
+ if (control->flags & LM_FLAG_CONTROL)
+ ret = stlc45xx_rx_control(stlc, skb);
+ else
+ ret = stlc45xx_rx_data(stlc, skb);
+
+ return ret;
+}
+
+
+static irqreturn_t stlc45xx_interrupt(int irq, void *config)
+{
+ struct spi_device *spi = config;
+ struct stlc45xx *stlc = dev_get_drvdata(&spi->dev);
+
+ stlc45xx_debug(DEBUG_IRQ, "IRQ");
+
+ queue_work(stlc->hw->workqueue, &stlc->work);
+
+ return IRQ_HANDLED;
+}
+
+static int stlc45xx_tx_frame(struct stlc45xx *stlc, u32 address,
+ void *buf, size_t len)
+{
+ struct s_dma_regs dma_regs;
+ unsigned long timeout;
+ int ret = 0;
+ u32 ints;
+
+ stlc->tx_frames++;
+
+ stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
+
+ stlc45xx_debug(DEBUG_TX, "tx frame 0x%p %d B", buf, len);
+ stlc45xx_dump(DEBUG_TX_CONTENT, buf, len);
+
+ stlc45xx_wakeup(stlc);
+
+ dma_regs.cmd = SPI_DMA_WRITE_CTRL_ENABLE;
+ dma_regs.len = cpu_to_le16(len);
+ dma_regs.addr = cpu_to_le32(address);
+
+ stlc45xx_spi_write(stlc, SPI_ADRS_DMA_WRITE_CTRL, &dma_regs,
+ sizeof(dma_regs));
+
+ stlc45xx_spi_write(stlc, SPI_ADRS_DMA_DATA, buf, len);
+
+ timeout = jiffies + 2 * HZ;
+ ints = stlc45xx_read32(stlc, SPI_ADRS_HOST_INTERRUPTS);
+ while (!(ints & SPI_HOST_INT_WR_READY)) {
+ if (time_after(jiffies, timeout)) {
+ stlc45xx_warning("WR_READY timeout");
+ ret = -1;
+ goto out;
+ }
+ ints = stlc45xx_read32(stlc, SPI_ADRS_HOST_INTERRUPTS);
+ }
+
+ stlc45xx_int_ack(stlc, SPI_HOST_INT_WR_READY);
+
+ stlc45xx_sleep(stlc);
+
+out:
+ return ret;
+}
+
+static int stlc45xx_wq_tx(struct stlc45xx *stlc)
+{
+ struct txbuffer *entry;
+ int ret = 0;
+
+ spin_lock_bh(&stlc->tx_lock);
+
+ while (!list_empty(&stlc->tx_pending)) {
+ entry = list_entry(stlc->tx_pending.next,
+ struct txbuffer, tx_list);
+
+ list_del_init(&entry->tx_list);
+
+ spin_unlock_bh(&stlc->tx_lock);
+
+ ret = stlc45xx_tx_frame(stlc, entry->frame_start,
+ entry->skb->data, entry->skb->len);
+
+ spin_lock_bh(&stlc->tx_lock);
+
+ if (ret < 0) {
+ /* frame transfer to firmware buffer failed */
+ /* FIXME: report this to mac80211 */
+ dev_kfree_skb(entry->skb);
+ stlc45xx_txbuffer_free(stlc, entry);
+ goto out;
+ }
+
+ list_add(&entry->tx_list, &stlc->tx_sent);
+ queue_delayed_work(stlc->hw->workqueue,
+ &stlc->work_tx_timeout,
+ msecs_to_jiffies(TX_TIMEOUT));
+ }
+
+out:
+ spin_unlock_bh(&stlc->tx_lock);
+ return ret;
+}
+
+static void stlc45xx_work(struct work_struct *work)
+{
+ struct stlc45xx *stlc = container_of(work, struct stlc45xx, work);
+ u32 ints;
+ int ret;
+
+ stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
+
+ mutex_lock(&stlc->mutex);
+
+ if (stlc->fw_state == FW_STATE_OFF &&
+ stlc->fw_state == FW_STATE_RESET)
+ goto out;
+
+ ints = stlc45xx_read32(stlc, SPI_ADRS_HOST_INTERRUPTS);
+ stlc45xx_debug(DEBUG_BH, "begin host_ints 0x%08x", ints);
+
+ if (ints & SPI_HOST_INT_READY) {
+ stlc45xx_int_ready(stlc);
+ stlc45xx_int_ack(stlc, SPI_HOST_INT_READY);
+ }
+
+ if (stlc->fw_state != FW_STATE_READY)
+ goto out;
+
+ if (ints & SPI_HOST_INT_UPDATE) {
+ stlc45xx_int_ack(stlc, SPI_HOST_INT_UPDATE);
+ ret = stlc45xx_rx(stlc);
+ if (ret < 0) {
+ stlc45xx_reset(stlc);
+ goto out;
+ }
+ }
+ if (ints & SPI_HOST_INT_SW_UPDATE) {
+ stlc45xx_int_ack(stlc, SPI_HOST_INT_SW_UPDATE);
+ ret = stlc45xx_rx(stlc);
+ if (ret < 0) {
+ stlc45xx_reset(stlc);
+ goto out;
+ }
+ }
+
+ ret = stlc45xx_wq_tx(stlc);
+ if (ret < 0) {
+ stlc45xx_reset(stlc);
+ goto out;
+ }
+
+ ints = stlc45xx_read32(stlc, SPI_ADRS_HOST_INTERRUPTS);
+ stlc45xx_debug(DEBUG_BH, "end host_ints 0x%08x", ints);
+
+out:
+ mutex_unlock(&stlc->mutex);
+}
+
+static void stlc45xx_tx_edcf(struct stlc45xx *stlc)
+{
+ struct s_lm_control *control;
+ struct s_lmo_edcf *edcf;
+ size_t len, edcf_len;
+
+ stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
+
+ edcf_len = sizeof(*edcf);
+ len = sizeof(*control) + edcf_len;
+ control = kzalloc(len, GFP_KERNEL);
+ edcf = (struct s_lmo_edcf *) (control + 1);
+
+ control->flags = LM_FLAG_CONTROL | LM_CTRL_OPSET;
+ control->length = edcf_len;
+ control->oid = LM_OID_EDCF;
+
+ edcf->slottime = 0x14;
+ edcf->sifs = 10;
+ edcf->eofpad = 6;
+ edcf->maxburst = 1500;
+
+ edcf->queues[0].aifs = 2;
+ edcf->queues[0].pad0 = 1;
+ edcf->queues[0].cwmin = 3;
+ edcf->queues[0].cwmax = 7;
+ edcf->queues[0].txop = 47;
+ edcf->queues[1].aifs = 2;
+ edcf->queues[1].pad0 = 0;
+ edcf->queues[1].cwmin = 7;
+ edcf->queues[1].cwmax = 15;
+ edcf->queues[1].txop = 94;
+ edcf->queues[2].aifs = 3;
+ edcf->queues[2].pad0 = 0;
+ edcf->queues[2].cwmin = 15;
+ edcf->queues[2].cwmax = 1023;
+ edcf->queues[2].txop = 0;
+ edcf->queues[3].aifs = 7;
+ edcf->queues[3].pad0 = 0;
+ edcf->queues[3].cwmin = 15;
+ edcf->queues[3].cwmax = 1023;
+ edcf->queues[3].txop = 0;
+ edcf->queues[4].aifs = 13;
+ edcf->queues[4].pad0 = 99;
+ edcf->queues[4].cwmin = 3437;
+ edcf->queues[4].cwmax = 512;
+ edcf->queues[4].txop = 12;
+ edcf->queues[5].aifs = 142;
+ edcf->queues[5].pad0 = 109;
+ edcf->queues[5].cwmin = 8756;
+ edcf->queues[5].cwmax = 6;
+ edcf->queues[5].txop = 0;
+ edcf->queues[6].aifs = 4;
+ edcf->queues[6].pad0 = 0;
+ edcf->queues[6].cwmin = 0;
+ edcf->queues[6].cwmax = 58705;
+ edcf->queues[6].txop = 25716;
+ edcf->queues[7].aifs = 0;
+ edcf->queues[7].pad0 = 0;
+ edcf->queues[7].cwmin = 0;
+ edcf->queues[7].cwmax = 0;
+ edcf->queues[7].txop = 0;
+
+ stlc45xx_tx_frame(stlc, FIRMWARE_CONFIG_START, control, len);
+
+ kfree(control);
+}
+
+static void stlc45xx_tx_setup(struct stlc45xx *stlc)
+{
+ struct s_lm_control *control;
+ struct s_lmo_setup *setup;
+ size_t len, setup_len;
+
+ stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
+
+ setup_len = sizeof(*setup);
+ len = sizeof(*control) + setup_len;
+ control = kzalloc(len, GFP_KERNEL);
+ setup = (struct s_lmo_setup *) (control + 1);
+
+ control->flags = LM_FLAG_CONTROL | LM_CTRL_OPSET;
+ control->length = setup_len;
+ control->oid = LM_OID_SETUP;
+
+ setup->flags = LM_SETUP_INFRA;
+ setup->antenna = 2;
+ setup->rx_align = 0;
+ setup->rx_buffer = FIRMWARE_RXBUFFER_START;
+ setup->rx_mtu = FIRMWARE_MTU;
+ setup->frontend = 5;
+ setup->timeout = 0;
+ setup->truncate = 48896;
+ setup->bratemask = 0xffffffff;
+ setup->ref_clock = 644245094;
+ setup->lpf_bandwidth = 65535;
+ setup->osc_start_delay = 65535;
+
+ memcpy(setup->macaddr, stlc->mac_addr, ETH_ALEN);
+ memcpy(setup->bssid, stlc->bssid, ETH_ALEN);
+
+ stlc45xx_tx_frame(stlc, FIRMWARE_CONFIG_START, control, len);
+
+ kfree(control);
+}
+
+static void stlc45xx_tx_scan(struct stlc45xx *stlc)
+{
+ struct s_lm_control *control;
+ struct s_lmo_scan *scan;
+ size_t len, scan_len;
+
+ stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
+
+ scan_len = sizeof(*scan);
+ len = sizeof(*control) + scan_len;
+ control = kzalloc(len, GFP_KERNEL);
+ scan = (struct s_lmo_scan *) (control + 1);
+
+ control->flags = LM_FLAG_CONTROL | LM_CTRL_OPSET;
+ control->length = scan_len;
+ control->oid = LM_OID_SCAN;
+
+ scan->flags = LM_SCAN_EXIT;
+ scan->bratemask = 0x15f;
+ scan->aloft[0] = 3;
+ scan->aloft[1] = 3;
+ scan->aloft[2] = 1;
+ scan->aloft[3] = 0;
+ scan->aloft[4] = 0;
+ scan->aloft[5] = 0;
+ scan->aloft[6] = 0;
+ scan->aloft[7] = 0;
+
+ memcpy(&scan->rssical, &stlc->cal_rssi[(stlc->channel - 1) *
+ RSSI_CAL_LEN],
+ RSSI_CAL_LEN);
+ memcpy(&scan->channel, &stlc->cal_channels[(stlc->channel - 1) *
+ CHANNEL_CAL_LEN],
+ CHANNEL_CAL_LEN);
+
+ stlc45xx_tx_frame(stlc, FIRMWARE_CONFIG_START, control, len);
+
+ kfree(control);
+}
+
+/*
+ * caller must hold mutex
+ */
+static int stlc45xx_tx_pspoll(struct stlc45xx *stlc, bool powersave)
+{
+ struct ieee80211_hdr *pspoll;
+ int payload_len, padding, i;
+ struct s_lm_data_out *data;
+ struct txbuffer *entry;
+ DECLARE_MAC_BUF(mac);
+ struct sk_buff *skb;
+ char *payload;
+ u16 fc;
+
+ skb = dev_alloc_skb(stlc->hw->extra_tx_headroom + 16);
+ if (!skb) {
+ stlc45xx_warning("failed to allocate pspoll frame");
+ return -ENOMEM;
+ }
+ skb_reserve(skb, stlc->hw->extra_tx_headroom);
+
+ pspoll = (struct ieee80211_hdr *) skb_put(skb, 16);
+ memset(pspoll, 0, 16);
+ fc = IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL;
+ if (powersave)
+ fc |= IEEE80211_FCTL_PM;
+ pspoll->frame_control = cpu_to_le16(fc);
+ pspoll->duration_id = cpu_to_le16(stlc->aid);
+
+ /* aid in PS-Poll has its two MSBs each set to 1 */
+ pspoll->duration_id |= cpu_to_le16(1 << 15) | cpu_to_le16(1 << 14);
+
+ memcpy(pspoll->addr1, stlc->bssid, ETH_ALEN);
+ memcpy(pspoll->addr2, stlc->mac_addr, ETH_ALEN);
+
+ stlc45xx_debug(DEBUG_PSM, "sending PS-Poll frame to %s (powersave %d, "
+ "fc 0x%x, aid %d)", print_mac(mac, pspoll->addr1),
+ powersave, fc, stlc->aid);
+
+ spin_lock_bh(&stlc->tx_lock);
+
+ entry = stlc45xx_txbuffer_alloc(stlc, skb->len);
+
+ spin_unlock_bh(&stlc->tx_lock);
+
+ if (!entry) {
+ /*
+ * The queue should be stopped before the firmware buffer
+ * is full, so firmware buffer should always have enough
+ * space.
+ *
+ * But I'm too lazy and omit it for now.
+ */
+ if (net_ratelimit())
+ stlc45xx_warning("firmware tx buffer full is full "
+ "for null frame");
+ return -ENOSPC;
+ }
+
+ payload = skb->data;
+ payload_len = skb->len;
+ padding = (int) (skb->data - sizeof(*data)) & 3;
+ entry->header_len = sizeof(*data) + padding;
+
+ entry->skb = skb;
+ entry->status_needed = false;
+ entry->handle = (u32) skb;
+ entry->lifetime = jiffies + msecs_to_jiffies(TX_FRAME_LIFETIME);
+
+ stlc45xx_debug(DEBUG_TX, "tx data 0x%x (0x%p payload %d B "
+ "padding %d header_len %d)",
+ entry->handle, payload, payload_len, padding,
+ entry->header_len);
+ stlc45xx_dump(DEBUG_TX_CONTENT, payload, payload_len);
+
+ data = (struct s_lm_data_out *) skb_push(skb, entry->header_len);
+
+ memset(data, 0, entry->header_len);
+
+ if (padding)
+ data->flags = LM_FLAG_ALIGN;
+
+ data->flags = LM_OUT_BURST;
+ data->length = payload_len;
+ data->handle = entry->handle;
+ data->aid = 1;
+ data->rts_retries = 7;
+ data->retries = 7;
+ data->aloft_ctrl = 0;
+ data->crypt_offset = 58;
+ data->keytype = 0;
+ data->keylen = 0;
+ data->queue = LM_QUEUE_DATA3;
+ data->backlog = 32;
+ data->antenna = 2;
+ data->cts = 3;
+ data->power = 127;
+
+ for (i = 0; i < 8; i++)
+ data->aloft[i] = 0;
+
+ /*
+ * check if there's enough space in tx buffer
+ *
+ * FIXME: ignored for now
+ */
+
+ stlc45xx_tx_frame(stlc, entry->start, skb->data, skb->len);
+
+ list_add(&entry->tx_list, &stlc->tx_sent);
+
+ return 0;
+}
+
+/*
+ * caller must hold mutex
+ *
+ * shamelessly stolen from mac80211/ieee80211_send_nullfunc
+ */
+static int stlc45xx_tx_nullfunc(struct stlc45xx *stlc, bool powersave)
+{
+ struct ieee80211_hdr *nullfunc;
+ int payload_len, padding, i;
+ struct s_lm_data_out *data;
+ struct txbuffer *entry;
+ DECLARE_MAC_BUF(mac);
+ struct sk_buff *skb;
+ char *payload;
+ u16 fc;
+
+ skb = dev_alloc_skb(stlc->hw->extra_tx_headroom + 24);
+ if (!skb) {
+ stlc45xx_warning("failed to allocate buffer for null frame\n");
+ return -ENOMEM;
+ }
+ skb_reserve(skb, stlc->hw->extra_tx_headroom);
+
+ nullfunc = (struct ieee80211_hdr *) skb_put(skb, 24);
+ memset(nullfunc, 0, 24);
+ fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC |
+ IEEE80211_FCTL_TODS;
+
+ if (powersave)
+ fc |= IEEE80211_FCTL_PM;
+
+ nullfunc->frame_control = cpu_to_le16(fc);
+ memcpy(nullfunc->addr1, stlc->bssid, ETH_ALEN);
+ memcpy(nullfunc->addr2, stlc->mac_addr, ETH_ALEN);
+ memcpy(nullfunc->addr3, stlc->bssid, ETH_ALEN);
+
+ stlc45xx_debug(DEBUG_PSM, "sending Null frame to %s (powersave %d, "
+ "fc 0x%x)",
+ print_mac(mac, nullfunc->addr1), powersave, fc);
+
+ spin_lock_bh(&stlc->tx_lock);
+
+ entry = stlc45xx_txbuffer_alloc(stlc, skb->len);
+
+ spin_unlock_bh(&stlc->tx_lock);
+
+ if (!entry) {
+ /*
+ * The queue should be stopped before the firmware buffer
+ * is full, so firmware buffer should always have enough
+ * space.
+ *
+ * But I'm too lazy and omit it for now.
+ */
+ if (net_ratelimit())
+ stlc45xx_warning("firmware tx buffer full is full "
+ "for null frame");
+ return -ENOSPC;
+ }
+
+ payload = skb->data;
+ payload_len = skb->len;
+ padding = (int) (skb->data - sizeof(*data)) & 3;
+ entry->header_len = sizeof(*data) + padding;
+
+ entry->skb = skb;
+ entry->status_needed = false;
+ entry->handle = (u32) skb;
+ entry->lifetime = jiffies + msecs_to_jiffies(TX_FRAME_LIFETIME);
+
+ stlc45xx_debug(DEBUG_TX, "tx data 0x%x (0x%p payload %d B "
+ "padding %d header_len %d)",
+ entry->handle, payload, payload_len, padding,
+ entry->header_len);
+ stlc45xx_dump(DEBUG_TX_CONTENT, payload, payload_len);
+
+ data = (struct s_lm_data_out *) skb_push(skb, entry->header_len);
+
+ memset(data, 0, entry->header_len);
+
+ if (padding)
+ data->flags = LM_FLAG_ALIGN;
+
+ data->flags = LM_OUT_BURST;
+ data->length = payload_len;
+ data->handle = entry->handle;
+ data->aid = 1;
+ data->rts_retries = 7;
+ data->retries = 7;
+ data->aloft_ctrl = 0;
+ data->crypt_offset = 58;
+ data->keytype = 0;
+ data->keylen = 0;
+ data->queue = LM_QUEUE_DATA3;
+ data->backlog = 32;
+ data->antenna = 2;
+ data->cts = 3;
+ data->power = 127;
+
+ for (i = 0; i < 8; i++)
+ data->aloft[i] = 0;
+
+ /*
+ * check if there's enough space in tx buffer
+ *
+ * FIXME: ignored for now
+ */
+
+ stlc45xx_tx_frame(stlc, entry->start, skb->data, skb->len);
+
+ list_add(&entry->tx_list, &stlc->tx_sent);
+
+ return 0;
+}
+
+/* caller must hold mutex */
+static void stlc45xx_tx_psm(struct stlc45xx *stlc, bool enable)
+{
+ struct s_lm_control *control;
+ struct s_lmo_psm *psm;
+ size_t len, psm_len;
+
+ WARN_ON(!stlc->associated);
+ WARN_ON(stlc->aid < 1);
+ WARN_ON(stlc->aid > 2007);
+
+ psm_len = sizeof(*psm);
+ len = sizeof(*control) + psm_len;
+ control = kzalloc(len, GFP_KERNEL);
+ psm = (struct s_lmo_psm *) (control + 1);
+
+ control->flags = LM_FLAG_CONTROL | LM_CTRL_OPSET;
+ control->length = psm_len;
+ control->oid = LM_OID_PSM;
+
+ if (enable)
+ psm->flags |= LM_PSM;
+
+ psm->aid = stlc->aid;
+
+ psm->beacon_rcpi_skip_max = 60;
+
+ psm->intervals[0].interval = 1;
+ psm->intervals[0].periods = 1;
+ psm->intervals[1].interval = 1;
+ psm->intervals[1].periods = 1;
+ psm->intervals[2].interval = 1;
+ psm->intervals[2].periods = 1;
+ psm->intervals[3].interval = 1;
+ psm->intervals[3].periods = 1;
+
+ psm->nr = 0;
+ psm->exclude[0] = 0;
+
+ stlc45xx_debug(DEBUG_PSM, "sending LM_OID_PSM (aid %d, interval %d)",
+ psm->aid, psm->intervals[0].interval);
+
+ stlc45xx_tx_frame(stlc, FIRMWARE_CONFIG_START, control, len);
+
+ kfree(control);
+}
+
+static int stlc45xx_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
+{
+ struct stlc45xx *stlc = hw->priv;
+ struct ieee80211_tx_info *info;
+ struct ieee80211_rate *rate;
+ int payload_len, padding, i;
+ struct s_lm_data_out *data;
+ struct txbuffer *entry;
+ char *payload;
+
+ stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
+
+ spin_lock_bh(&stlc->tx_lock);
+
+ entry = stlc45xx_txbuffer_alloc(stlc, skb->len);
+ if (!entry) {
+ /* the queue should be stopped before the firmware buffer
+ * is full, so firmware buffer should always have enough
+ * space */
+ if (net_ratelimit())
+ stlc45xx_warning("firmware buffer full");
+ spin_unlock_bh(&stlc->tx_lock);
+ return NETDEV_TX_BUSY;
+ }
+
+ info = IEEE80211_SKB_CB(skb);
+
+ payload = skb->data;
+ payload_len = skb->len;
+ padding = (int) (skb->data - sizeof(*data)) & 3;
+ entry->header_len = sizeof(*data) + padding;
+
+ entry->skb = skb;
+ entry->status_needed = true;
+ entry->handle = (u32) skb;
+ entry->lifetime = jiffies + msecs_to_jiffies(TX_FRAME_LIFETIME);
+
+ stlc45xx_debug(DEBUG_TX, "tx data 0x%x (0x%p payload %d B "
+ "padding %d header_len %d)",
+ entry->handle, payload, payload_len, padding,
+ entry->header_len);
+ stlc45xx_dump(DEBUG_TX_CONTENT, payload, payload_len);
+
+ data = (struct s_lm_data_out *) skb_push(skb, entry->header_len);
+
+ memset(data, 0, entry->header_len);
+
+ if (padding)
+ data->flags = LM_FLAG_ALIGN;
+
+ data->flags = LM_OUT_BURST;
+ data->length = payload_len;
+ data->handle = entry->handle;
+ data->aid = 1;
+ data->rts_retries = 7;
+ data->retries = 7;
+ data->aloft_ctrl = 0;
+ data->crypt_offset = 58;
+ data->keytype = 0;
+ data->keylen = 0;
+ data->queue = 2;
+ data->backlog = 32;
+ data->antenna = 2;
+ data->cts = 3;
+ data->power = 127;
+
+ for (i = 0; i < 8; i++) {
+ rate = ieee80211_get_tx_rate(stlc->hw, info);
+ data->aloft[i] = rate->hw_value;
+ }
+
+ list_add_tail(&entry->tx_list, &stlc->tx_pending);
+
+ /* check if there's enough space in tx buffer */
+ if (stlc45xx_txbuffer_find(stlc, MAX_FRAME_LEN) == -1) {
+ stlc45xx_debug(DEBUG_QUEUE, "tx buffer full, stopping queues");
+ stlc->tx_queue_stopped = 1;
+ ieee80211_stop_queues(stlc->hw);
+ }
+
+ queue_work(stlc->hw->workqueue, &stlc->work);
+
+ spin_unlock_bh(&stlc->tx_lock);
+
+ return NETDEV_TX_OK;
+}
+
+static int stlc45xx_op_start(struct ieee80211_hw *hw)
+{
+ struct stlc45xx *stlc = hw->priv;
+ unsigned long timeout;
+ int ret = 0;
+
+ stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
+
+ mutex_lock(&stlc->mutex);
+
+ stlc->fw_state = FW_STATE_BOOTING;
+ stlc->channel = 1;
+
+ stlc45xx_power_on(stlc);
+
+ ret = stlc45xx_upload_firmware(stlc);
+ if (ret < 0) {
+ stlc45xx_power_off(stlc);
+ goto out_unlock;
+ }
+
+ stlc->tx_queue_stopped = 0;
+
+ mutex_unlock(&stlc->mutex);
+
+ timeout = msecs_to_jiffies(2000);
+ timeout = wait_for_completion_interruptible_timeout(&stlc->fw_comp,
+ timeout);
+ if (!timeout) {
+ stlc45xx_error("firmware boot failed");
+ stlc45xx_power_off(stlc);
+ ret = -1;
+ goto out;
+ }
+
+ stlc45xx_debug(DEBUG_BOOT, "firmware booted");
+
+ /* FIXME: should we take mutex just after wait_for_completion()? */
+ mutex_lock(&stlc->mutex);
+
+ WARN_ON(stlc->fw_state != FW_STATE_READY);
+
+out_unlock:
+ mutex_unlock(&stlc->mutex);
+
+out:
+ return ret;
+}
+
+static void stlc45xx_op_stop(struct ieee80211_hw *hw)
+{
+ struct stlc45xx *stlc = hw->priv;
+
+ stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
+
+ mutex_lock(&stlc->mutex);
+
+ WARN_ON(stlc->fw_state != FW_STATE_READY);
+
+ stlc45xx_power_off(stlc);
+
+ /* FIXME: make sure that all work_structs have completed */
+
+ spin_lock_bh(&stlc->tx_lock);
+ stlc45xx_flush_queues(stlc);
+ spin_unlock_bh(&stlc->tx_lock);
+
+ stlc->fw_state = FW_STATE_OFF;
+
+ mutex_unlock(&stlc->mutex);
+}
+
+static int stlc45xx_op_add_interface(struct ieee80211_hw *hw,
+ struct ieee80211_if_init_conf *conf)
+{
+ struct stlc45xx *stlc = hw->priv;
+
+ stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
+
+ switch (conf->type) {
+ case NL80211_IFTYPE_STATION:
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ memcpy(stlc->mac_addr, conf->mac_addr, ETH_ALEN);
+
+ return 0;
+}
+
+static void stlc45xx_op_remove_interface(struct ieee80211_hw *hw,
+ struct ieee80211_if_init_conf *conf)
+{
+ stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
+}
+
+static int stlc45xx_op_config_interface(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_if_conf *conf)
+{
+ struct stlc45xx *stlc = hw->priv;
+
+ stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
+
+ mutex_lock(&stlc->mutex);
+
+ memcpy(stlc->bssid, conf->bssid, ETH_ALEN);
+ stlc45xx_tx_setup(stlc);
+
+ mutex_unlock(&stlc->mutex);
+
+ return 0;
+}
+
+static int stlc45xx_op_config(struct ieee80211_hw *hw, u32 changed)
+{
+ struct stlc45xx *stlc = hw->priv;
+
+ stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
+
+ mutex_lock(&stlc->mutex);
+
+ stlc->channel = hw->conf.channel->hw_value;
+ stlc45xx_tx_scan(stlc);
+ stlc45xx_tx_setup(stlc);
+ stlc45xx_tx_edcf(stlc);
+
+ if ((hw->conf.flags & IEEE80211_CONF_PS) != stlc->psm) {
+ stlc->psm = hw->conf.flags & IEEE80211_CONF_PS;
+ if (stlc->associated) {
+ stlc45xx_tx_psm(stlc, stlc->psm);
+ stlc45xx_tx_nullfunc(stlc, stlc->psm);
+ }
+ }
+
+ mutex_unlock(&stlc->mutex);
+
+ return 0;
+}
+
+static void stlc45xx_op_configure_filter(struct ieee80211_hw *hw,
+ unsigned int changed_flags,
+ unsigned int *total_flags,
+ int mc_count,
+ struct dev_addr_list *mc_list)
+{
+ *total_flags = 0;
+}
+
+static void stlc45xx_op_bss_info_changed(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_bss_conf *info,
+ u32 changed)
+{
+ struct stlc45xx *stlc = hw->priv;
+
+ if (changed & BSS_CHANGED_ASSOC) {
+ stlc->associated = info->assoc;
+ if (info->assoc)
+ stlc->aid = info->aid;
+ else
+ stlc->aid = -1;
+
+ if (stlc->psm) {
+ stlc45xx_tx_psm(stlc, stlc->psm);
+ stlc45xx_tx_nullfunc(stlc, stlc->psm);
+ }
+ }
+}
+
+
+/* can't be const, mac80211 writes to this */
+static struct ieee80211_rate stlc45xx_rates[] = {
+ { .bitrate = 10, .hw_value = 0, .hw_value_short = 0, },
+ { .bitrate = 20, .hw_value = 1, .hw_value_short = 1, },
+ { .bitrate = 55, .hw_value = 2, .hw_value_short = 2, },
+ { .bitrate = 110, .hw_value = 3, .hw_value_short = 3, },
+ { .bitrate = 60, .hw_value = 4, .hw_value_short = 4, },
+ { .bitrate = 90, .hw_value = 5, .hw_value_short = 5, },
+ { .bitrate = 120, .hw_value = 6, .hw_value_short = 6, },
+ { .bitrate = 180, .hw_value = 7, .hw_value_short = 7, },
+ { .bitrate = 240, .hw_value = 8, .hw_value_short = 8, },
+ { .bitrate = 360, .hw_value = 9, .hw_value_short = 9, },
+ { .bitrate = 480, .hw_value = 10, .hw_value_short = 10, },
+ { .bitrate = 540, .hw_value = 11, .hw_value_short = 11, },
+};
+
+/* can't be const, mac80211 writes to this */
+static struct ieee80211_channel stlc45xx_channels[] = {
+ { .hw_value = 1, .center_freq = 2412},
+ { .hw_value = 2, .center_freq = 2417},
+ { .hw_value = 3, .center_freq = 2422},
+ { .hw_value = 4, .center_freq = 2427},
+ { .hw_value = 5, .center_freq = 2432},
+ { .hw_value = 6, .center_freq = 2437},
+ { .hw_value = 7, .center_freq = 2442},
+ { .hw_value = 8, .center_freq = 2447},
+ { .hw_value = 9, .center_freq = 2452},
+ { .hw_value = 10, .center_freq = 2457},
+ { .hw_value = 11, .center_freq = 2462},
+ { .hw_value = 12, .center_freq = 2467},
+ { .hw_value = 13, .center_freq = 2472},
+};
+
+/* can't be const, mac80211 writes to this */
+static struct ieee80211_supported_band stlc45xx_band_2ghz = {
+ .channels = stlc45xx_channels,
+ .n_channels = ARRAY_SIZE(stlc45xx_channels),
+ .bitrates = stlc45xx_rates,
+ .n_bitrates = ARRAY_SIZE(stlc45xx_rates),
+};
+
+static const struct ieee80211_ops stlc45xx_ops = {
+ .start = stlc45xx_op_start,
+ .stop = stlc45xx_op_stop,
+ .add_interface = stlc45xx_op_add_interface,
+ .remove_interface = stlc45xx_op_remove_interface,
+ .config = stlc45xx_op_config,
+ .config_interface = stlc45xx_op_config_interface,
+ .configure_filter = stlc45xx_op_configure_filter,
+ .tx = stlc45xx_op_tx,
+ .bss_info_changed = stlc45xx_op_bss_info_changed,
+};
+
+static int stlc45xx_register_mac80211(struct stlc45xx *stlc)
+{
+ /* FIXME: SET_IEEE80211_PERM_ADDR() requires default_mac_addr
+ to be non-const for some strange reason */
+ static u8 default_mac_addr[ETH_ALEN] = {
+ 0x00, 0x02, 0xee, 0xc0, 0xff, 0xee
+ };
+ int ret;
+
+ SET_IEEE80211_PERM_ADDR(stlc->hw, default_mac_addr);
+
+ ret = ieee80211_register_hw(stlc->hw);
+ if (ret) {
+ stlc45xx_error("unable to register mac80211 hw: %d", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void stlc45xx_device_release(struct device *dev)
+{
+
+}
+
+static struct platform_device stlc45xx_device = {
+ .name = "stlc45xx",
+ .id = -1,
+
+ /* device model insists to have a release function */
+ .dev = {
+ .release = stlc45xx_device_release,
+ },
+};
+
+static int __devinit stlc45xx_probe(struct spi_device *spi)
+{
+ struct stlc45xx *stlc;
+ struct ieee80211_hw *hw;
+ int ret;
+
+ stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
+
+ /* mac80211 alloc */
+ hw = ieee80211_alloc_hw(sizeof(*stlc), &stlc45xx_ops);
+ if (!hw) {
+ stlc45xx_error("could not alloc ieee80211_hw");
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /* mac80211 clears hw->priv */
+ stlc = hw->priv;
+
+ stlc->hw = hw;
+ dev_set_drvdata(&spi->dev, stlc);
+ stlc->spi = spi;
+
+ spi->bits_per_word = 16;
+ spi->max_speed_hz = 24000000;
+
+ ret = spi_setup(spi);
+ if (ret < 0)
+ stlc45xx_error("spi_setup failed");
+
+ ret = gpio_request(stlc45xx_gpio_power, "stlc45xx power");
+ if (ret < 0) {
+ stlc45xx_error("power GPIO request failed: %d", ret);
+ return ret;
+ }
+
+ ret = gpio_request(stlc45xx_gpio_irq, "stlc45xx irq");
+ if (ret < 0) {
+ stlc45xx_error("irq GPIO request failed: %d", ret);
+ goto out;
+ }
+
+ gpio_direction_output(stlc45xx_gpio_power, 0);
+ gpio_direction_input(stlc45xx_gpio_irq);
+
+ ret = request_irq(gpio_to_irq(stlc45xx_gpio_irq),
+ stlc45xx_interrupt, IRQF_DISABLED, "stlc45xx",
+ stlc->spi);
+ if (ret < 0)
+ /* FIXME: handle the error */
+ stlc45xx_error("request_irq() failed");
+
+ set_irq_type(gpio_to_irq(stlc45xx_gpio_irq),
+ IRQ_TYPE_EDGE_RISING);
+
+ disable_irq(gpio_to_irq(stlc45xx_gpio_irq));
+
+ ret = platform_device_register(&stlc45xx_device);
+ if (ret) {
+ stlc45xx_error("Couldn't register wlan_omap device.");
+ return ret;
+ }
+ dev_set_drvdata(&stlc45xx_device.dev, stlc);
+
+ INIT_WORK(&stlc->work, stlc45xx_work);
+ INIT_WORK(&stlc->work_reset, stlc45xx_work_reset);
+ INIT_DELAYED_WORK(&stlc->work_tx_timeout, stlc45xx_work_tx_timeout);
+ mutex_init(&stlc->mutex);
+ init_completion(&stlc->fw_comp);
+ spin_lock_init(&stlc->tx_lock);
+ INIT_LIST_HEAD(&stlc->txbuffer);
+ INIT_LIST_HEAD(&stlc->tx_pending);
+ INIT_LIST_HEAD(&stlc->tx_sent);
+
+ hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
+ IEEE80211_HW_SIGNAL_DBM |
+ IEEE80211_HW_NOISE_DBM;
+ /* four bytes for padding */
+ hw->extra_tx_headroom = sizeof(struct s_lm_data_out) + 4;
+
+ /* unit us */
+ hw->channel_change_time = 1000;
+
+ hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
+ hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &stlc45xx_band_2ghz;
+
+ SET_IEEE80211_DEV(hw, &spi->dev);
+
+ BUILD_BUG_ON(sizeof(default_cal_rssi) != RSSI_CAL_ARRAY_LEN);
+ BUILD_BUG_ON(sizeof(default_cal_channels) != CHANNEL_CAL_ARRAY_LEN);
+
+ stlc->cal_rssi = kmemdup(default_cal_rssi, RSSI_CAL_ARRAY_LEN,
+ GFP_KERNEL);
+ stlc->cal_channels = kmemdup(default_cal_channels,
+ CHANNEL_CAL_ARRAY_LEN,
+ GFP_KERNEL);
+
+ ret = device_create_file(&stlc45xx_device.dev, &dev_attr_cal_rssi);
+ if (ret < 0) {
+ stlc45xx_error("failed to create sysfs file cal_rssi");
+ goto out;
+ }
+
+ ret = device_create_file(&stlc45xx_device.dev, &dev_attr_cal_channels);
+ if (ret < 0) {
+ stlc45xx_error("failed to create sysfs file cal_channels");
+ goto out;
+ }
+
+ ret = device_create_file(&stlc45xx_device.dev, &dev_attr_tx_buf);
+ if (ret < 0) {
+ stlc45xx_error("failed to create sysfs file tx_buf");
+ goto out;
+ }
+
+ ret = stlc45xx_register_mac80211(stlc);
+ if (ret < 0)
+ goto out;
+
+ stlc45xx_info("v" DRIVER_VERSION " loaded");
+
+ stlc45xx_info("config buffer 0x%x-0x%x",
+ FIRMWARE_CONFIG_START, FIRMWARE_CONFIG_END);
+ stlc45xx_info("tx 0x%x-0x%x, rx 0x%x-0x%x",
+ FIRMWARE_TXBUFFER_START, FIRMWARE_TXBUFFER_END,
+ FIRMWARE_RXBUFFER_START, FIRMWARE_RXBUFFER_END);
+
+out:
+ return ret;
+}
+
+static int __devexit stlc45xx_remove(struct spi_device *spi)
+{
+ struct stlc45xx *stlc = dev_get_drvdata(&spi->dev);
+
+ stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
+
+ platform_device_unregister(&stlc45xx_device);
+
+ ieee80211_unregister_hw(stlc->hw);
+
+ free_irq(gpio_to_irq(stlc45xx_gpio_irq), spi);
+
+ gpio_free(stlc45xx_gpio_power);
+ gpio_free(stlc45xx_gpio_irq);
+
+ /* FIXME: free cal_channels and cal_rssi? */
+
+ kfree(stlc->fw);
+
+ mutex_destroy(&stlc->mutex);
+
+ /* frees also stlc */
+ ieee80211_free_hw(stlc->hw);
+ stlc = NULL;
+
+ return 0;
+}
+
+
+static struct spi_driver stlc45xx_spi_driver = {
+ .driver = {
+ /* use cx3110x name because board-n800.c uses that for the
+ * SPI port */
+ .name = "cx3110x",
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ },
+
+ .probe = stlc45xx_probe,
+ .remove = __devexit_p(stlc45xx_remove),
+};
+
+static int __init stlc45xx_init(void)
+{
+ int ret;
+
+ stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
+
+ ret = spi_register_driver(&stlc45xx_spi_driver);
+ if (ret < 0) {
+ stlc45xx_error("failed to register SPI driver: %d", ret);
+ goto out;
+ }
+
+out:
+ return ret;
+}
+
+static void __exit stlc45xx_exit(void)
+{
+ stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
+
+ spi_unregister_driver(&stlc45xx_spi_driver);
+
+ stlc45xx_info("unloaded");
+}
+
+module_init(stlc45xx_init);
+module_exit(stlc45xx_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Kalle Valo <kalle.valo@nokia.com>");
diff --git a/drivers/staging/stlc45xx/stlc45xx.h b/drivers/staging/stlc45xx/stlc45xx.h
new file mode 100644
index 000000000000..ac96bbbde79f
--- /dev/null
+++ b/drivers/staging/stlc45xx/stlc45xx.h
@@ -0,0 +1,283 @@
+/*
+ * This file is part of stlc45xx
+ *
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * Contact: Kalle Valo <kalle.valo@nokia.com>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/mutex.h>
+#include <linux/list.h>
+#include <net/mac80211.h>
+
+#include "stlc45xx_lmac.h"
+
+#define DRIVER_NAME "stlc45xx"
+#define DRIVER_VERSION "0.1.3"
+
+#define DRIVER_PREFIX DRIVER_NAME ": "
+
+enum {
+ DEBUG_NONE = 0,
+ DEBUG_FUNC = 1 << 0,
+ DEBUG_IRQ = 1 << 1,
+ DEBUG_BH = 1 << 2,
+ DEBUG_RX = 1 << 3,
+ DEBUG_RX_CONTENT = 1 << 5,
+ DEBUG_TX = 1 << 6,
+ DEBUG_TX_CONTENT = 1 << 8,
+ DEBUG_TXBUFFER = 1 << 9,
+ DEBUG_QUEUE = 1 << 10,
+ DEBUG_BOOT = 1 << 11,
+ DEBUG_PSM = 1 << 12,
+ DEBUG_ALL = ~0,
+};
+
+#define DEBUG_LEVEL DEBUG_NONE
+/* #define DEBUG_LEVEL DEBUG_ALL */
+/* #define DEBUG_LEVEL (DEBUG_TX | DEBUG_RX | DEBUG_IRQ) */
+/* #define DEBUG_LEVEL (DEBUG_TX | DEBUG_MEMREGION | DEBUG_QUEUE) */
+/* #define DEBUG_LEVEL (DEBUG_MEMREGION | DEBUG_QUEUE) */
+
+#define stlc45xx_error(fmt, arg...) \
+ printk(KERN_ERR DRIVER_PREFIX "ERROR " fmt "\n", ##arg)
+
+#define stlc45xx_warning(fmt, arg...) \
+ printk(KERN_WARNING DRIVER_PREFIX "WARNING " fmt "\n", ##arg)
+
+#define stlc45xx_info(fmt, arg...) \
+ printk(KERN_INFO DRIVER_PREFIX fmt "\n", ##arg)
+
+#define stlc45xx_debug(level, fmt, arg...) \
+ do { \
+ if (level & DEBUG_LEVEL) \
+ printk(KERN_DEBUG DRIVER_PREFIX fmt "\n", ##arg); \
+ } while (0)
+
+#define stlc45xx_dump(level, buf, len) \
+ do { \
+ if (level & DEBUG_LEVEL) \
+ print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, \
+ 16, 1, buf, len, 1); \
+ } while (0)
+
+#define MAC2STR(a) ((a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5])
+#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
+
+/* Bit 15 is read/write bit; ON = READ, OFF = WRITE */
+#define ADDR_READ_BIT_15 0x8000
+
+#define SPI_ADRS_ARM_INTERRUPTS 0x00
+#define SPI_ADRS_ARM_INT_EN 0x04
+
+#define SPI_ADRS_HOST_INTERRUPTS 0x08
+#define SPI_ADRS_HOST_INT_EN 0x0c
+#define SPI_ADRS_HOST_INT_ACK 0x10
+
+#define SPI_ADRS_GEN_PURP_1 0x14
+#define SPI_ADRS_GEN_PURP_2 0x18
+
+/* high word */
+#define SPI_ADRS_DEV_CTRL_STAT 0x26
+
+#define SPI_ADRS_DMA_DATA 0x28
+
+#define SPI_ADRS_DMA_WRITE_CTRL 0x2c
+#define SPI_ADRS_DMA_WRITE_LEN 0x2e
+#define SPI_ADRS_DMA_WRITE_BASE 0x30
+
+#define SPI_ADRS_DMA_READ_CTRL 0x34
+#define SPI_ADRS_DMA_READ_LEN 0x36
+#define SPI_ADRS_DMA_READ_BASE 0x38
+
+#define SPI_CTRL_STAT_HOST_OVERRIDE 0x8000
+#define SPI_CTRL_STAT_START_HALTED 0x4000
+#define SPI_CTRL_STAT_RAM_BOOT 0x2000
+#define SPI_CTRL_STAT_HOST_RESET 0x1000
+#define SPI_CTRL_STAT_HOST_CPU_EN 0x0800
+
+#define SPI_DMA_WRITE_CTRL_ENABLE 0x0001
+#define SPI_DMA_READ_CTRL_ENABLE 0x0001
+#define HOST_ALLOWED (1 << 7)
+
+#define FIRMWARE_ADDRESS 0x20000
+
+#define SPI_TIMEOUT 100 /* msec */
+
+#define SPI_MAX_TX_PACKETS 32
+
+#define SPI_MAX_PACKET_SIZE 32767
+
+#define SPI_TARGET_INT_WAKEUP 0x00000001
+#define SPI_TARGET_INT_SLEEP 0x00000002
+#define SPI_TARGET_INT_RDDONE 0x00000004
+
+#define SPI_TARGET_INT_CTS 0x00004000
+#define SPI_TARGET_INT_DR 0x00008000
+
+#define SPI_HOST_INT_READY 0x00000001
+#define SPI_HOST_INT_WR_READY 0x00000002
+#define SPI_HOST_INT_SW_UPDATE 0x00000004
+#define SPI_HOST_INT_UPDATE 0x10000000
+
+/* clear to send */
+#define SPI_HOST_INT_CTS 0x00004000
+
+/* data ready */
+#define SPI_HOST_INT_DR 0x00008000
+
+#define SPI_HOST_INTS_DEFAULT \
+ (SPI_HOST_INT_READY | SPI_HOST_INT_UPDATE | SPI_HOST_INT_SW_UPDATE)
+
+#define TARGET_BOOT_SLEEP 50
+
+/* The firmware buffer is divided into three areas:
+ *
+ * o config area (for control commands)
+ * o tx buffer
+ * o rx buffer
+ */
+#define FIRMWARE_BUFFER_START 0x20200
+#define FIRMWARE_BUFFER_END 0x27c60
+#define FIRMWARE_BUFFER_LEN (FIRMWARE_BUFFER_END - FIRMWARE_BUFFER_START)
+#define FIRMWARE_MTU 3240
+#define FIRMWARE_CONFIG_PAYLOAD_LEN 1024
+#define FIRMWARE_CONFIG_START FIRMWARE_BUFFER_START
+#define FIRMWARE_CONFIG_LEN (sizeof(struct s_lm_control) + \
+ FIRMWARE_CONFIG_PAYLOAD_LEN)
+#define FIRMWARE_CONFIG_END (FIRMWARE_CONFIG_START + FIRMWARE_CONFIG_LEN - 1)
+#define FIRMWARE_RXBUFFER_LEN (5 * FIRMWARE_MTU + 1024)
+#define FIRMWARE_RXBUFFER_START (FIRMWARE_BUFFER_END - FIRMWARE_RXBUFFER_LEN)
+#define FIRMWARE_RXBUFFER_END (FIRMWARE_RXBUFFER_START + \
+ FIRMWARE_RXBUFFER_LEN - 1)
+#define FIRMWARE_TXBUFFER_START (FIRMWARE_BUFFER_START + FIRMWARE_CONFIG_LEN)
+#define FIRMWARE_TXBUFFER_LEN (FIRMWARE_BUFFER_LEN - FIRMWARE_CONFIG_LEN - \
+ FIRMWARE_RXBUFFER_LEN)
+#define FIRMWARE_TXBUFFER_END (FIRMWARE_TXBUFFER_START + \
+ FIRMWARE_TXBUFFER_LEN - 1)
+
+#define FIRMWARE_TXBUFFER_HEADER 100
+#define FIRMWARE_TXBUFFER_TRAILER 4
+
+/* FIXME: come up with a proper value */
+#define MAX_FRAME_LEN 2500
+
+/* unit is ms */
+#define TX_FRAME_LIFETIME 2000
+#define TX_TIMEOUT 4000
+
+#define SUPPORTED_CHANNELS 13
+
+/* FIXME */
+/* #define CHANNEL_CAL_LEN offsetof(struct s_lmo_scan, bratemask) - \ */
+/* offsetof(struct s_lmo_scan, channel) */
+#define CHANNEL_CAL_LEN 292
+#define CHANNEL_CAL_ARRAY_LEN (SUPPORTED_CHANNELS * CHANNEL_CAL_LEN)
+/* FIXME */
+/* #define RSSI_CAL_LEN sizeof(struct s_lmo_scan) - \ */
+/* offsetof(struct s_lmo_scan, rssical) */
+#define RSSI_CAL_LEN 8
+#define RSSI_CAL_ARRAY_LEN (SUPPORTED_CHANNELS * RSSI_CAL_LEN)
+
+struct s_dma_regs {
+ unsigned short cmd;
+ unsigned short len;
+ unsigned long addr;
+};
+
+struct stlc45xx_ie_tim {
+ u8 dtim_count;
+ u8 dtim_period;
+ u8 bmap_control;
+ u8 pvbmap[251];
+};
+
+struct txbuffer {
+ /* can be removed when switched to skb queue */
+ struct list_head tx_list;
+
+ struct list_head buffer_list;
+
+ int start;
+ int frame_start;
+ int end;
+
+ struct sk_buff *skb;
+ u32 handle;
+
+ bool status_needed;
+
+ int header_len;
+
+ /* unit jiffies */
+ unsigned long lifetime;
+};
+
+enum fw_state {
+ FW_STATE_OFF,
+ FW_STATE_BOOTING,
+ FW_STATE_READY,
+ FW_STATE_RESET,
+ FW_STATE_RESETTING,
+};
+
+struct stlc45xx {
+ struct ieee80211_hw *hw;
+ struct spi_device *spi;
+ struct work_struct work;
+ struct work_struct work_reset;
+ struct delayed_work work_tx_timeout;
+ struct mutex mutex;
+ struct completion fw_comp;
+
+
+ u8 bssid[ETH_ALEN];
+ u8 mac_addr[ETH_ALEN];
+ int channel;
+
+ u8 *cal_rssi;
+ u8 *cal_channels;
+
+ enum fw_state fw_state;
+
+ spinlock_t tx_lock;
+
+ /* protected by tx_lock */
+ struct list_head txbuffer;
+
+ /* protected by tx_lock */
+ struct list_head tx_pending;
+
+ /* protected by tx_lock */
+ int tx_queue_stopped;
+
+ /* protected by mutex */
+ struct list_head tx_sent;
+
+ int tx_frames;
+
+ u8 *fw;
+ int fw_len;
+
+ bool psm;
+ bool associated;
+ int aid;
+ bool pspolling;
+};
+
+
diff --git a/drivers/staging/stlc45xx/stlc45xx_lmac.h b/drivers/staging/stlc45xx/stlc45xx_lmac.h
new file mode 100644
index 000000000000..af5db801347f
--- /dev/null
+++ b/drivers/staging/stlc45xx/stlc45xx_lmac.h
@@ -0,0 +1,434 @@
+/************************************************************************
+* This is the LMAC API interface header file for STLC4560. *
+* Copyright (C) 2007 Conexant Systems, Inc. *
+* This program is free software; you can redistribute it and/or *
+* modify it under the terms of the GNU General Public License *
+* as published by the Free Software Foundation; either version 2 *
+* of the License, or (at your option) any later version. *
+* *
+* This program is distributed in the hope that it will be useful, *
+* but WITHOUT ANY WARRANTY; without even the implied warranty of *
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+* GNU General Public License for more details. *
+* *
+* You should have received a copy of the GNU General Public License *
+* along with this program. If not, see <http://www.gnu.org/licenses/>.*
+*************************************************************************/
+
+#ifndef __lmac_h__
+#define __lmac_h__
+
+#define LM_TOP_VARIANT 0x0506
+#define LM_BOTTOM_VARIANT 0x0506
+
+/*
+ * LMAC - UMAC interface definition:
+ */
+
+#define LM_FLAG_CONTROL 0x8000
+#define LM_FLAG_ALIGN 0x4000
+
+#define LM_CTRL_OPSET 0x0001
+
+#define LM_OUT_PROMISC 0x0001
+#define LM_OUT_TIMESTAMP 0x0002
+#define LM_OUT_SEQNR 0x0004
+#define LM_OUT_BURST 0x0010
+#define LM_OUT_NOCANCEL 0x0020
+#define LM_OUT_CLEARTIM 0x0040
+#define LM_OUT_HITCHHIKE 0x0080
+#define LM_OUT_COMPRESS 0x0100
+#define LM_OUT_CONCAT 0x0200
+#define LM_OUT_PCS_ACCEPT 0x0400
+#define LM_OUT_WAITEOSP 0x0800
+
+
+#define LM_ALOFT_SP 0x10
+#define LM_ALOFT_CTS 0x20
+#define LM_ALOFT_RTS 0x40
+#define LM_ALOFT_MASK 0x1f
+#define LM_ALOFT_RATE 0x0f
+
+#define LM_IN_FCS_GOOD 0x0001
+#define LM_IN_MATCH_MAC 0x0002
+#define LM_IN_MCBC 0x0004
+#define LM_IN_BEACON 0x0008
+#define LM_IN_MATCH_BSS 0x0010
+#define LM_IN_BCAST_BSS 0x0020
+#define LM_IN_DATA 0x0040
+#define LM_IN_TRUNCATED 0x0080
+
+#define LM_IN_TRANSPARENT 0x0200
+
+#define LM_QUEUE_BEACON 0
+#define LM_QUEUE_SCAN 1
+#define LM_QUEUE_MGT 2
+#define LM_QUEUE_MCBC 3
+#define LM_QUEUE_DATA 4
+#define LM_QUEUE_DATA0 4
+#define LM_QUEUE_DATA1 5
+#define LM_QUEUE_DATA2 6
+#define LM_QUEUE_DATA3 7
+
+#define LM_SETUP_INFRA 0x0001
+#define LM_SETUP_IBSS 0x0002
+#define LM_SETUP_TRANSPARENT 0x0008
+#define LM_SETUP_PROMISCUOUS 0x0010
+#define LM_SETUP_HIBERNATE 0x0020
+#define LM_SETUP_NOACK 0x0040
+#define LM_SETUP_RX_DISABLED 0x0080
+
+#define LM_ANTENNA_0 0
+#define LM_ANTENNA_1 1
+#define LM_ANTENNA_DIVERSITY 2
+
+#define LM_TX_FAILED 0x0001
+#define LM_TX_PSM 0x0002
+#define LM_TX_PSM_CANCELLED 0x0004
+
+#define LM_SCAN_EXIT 0x0001
+#define LM_SCAN_TRAP 0x0002
+#define LM_SCAN_ACTIVE 0x0004
+#define LM_SCAN_FILTER 0x0008
+
+#define LM_PSM 0x0001
+#define LM_PSM_DTIM 0x0002
+#define LM_PSM_MCBC 0x0004
+#define LM_PSM_CHECKSUM 0x0008
+#define LM_PSM_SKIP_MORE_DATA 0x0010
+#define LM_PSM_BEACON_TIMEOUT 0x0020
+#define LM_PSM_HFOSLEEP 0x0040
+#define LM_PSM_AUTOSWITCH_SLEEP 0x0080
+#define LM_PSM_LPIT 0x0100
+#define LM_PSM_BF_UCAST_SKIP 0x0200
+#define LM_PSM_BF_MCAST_SKIP 0x0400
+
+/* hfosleep */
+#define LM_PSM_SLEEP_OPTION_MASK (LM_PSM_AUTOSWITCH_SLEEP | LM_PSM_HFOSLEEP)
+#define LM_PSM_SLEEP_OPTION_SHIFT 6
+/* hfosleepend */
+#define LM_PSM_BF_OPTION_MASK (LM_PSM_BF_MCAST_SKIP | LM_PSM_BF_UCAST_SKIP)
+#define LM_PSM_BF_OPTION_SHIFT 9
+
+
+#define LM_PRIVACC_WEP 0x01
+#define LM_PRIVACC_TKIP 0x02
+#define LM_PRIVACC_MICHAEL 0x04
+#define LM_PRIVACC_CCX_KP 0x08
+#define LM_PRIVACC_CCX_MIC 0x10
+#define LM_PRIVACC_AES_CCMP 0x20
+
+/* size of s_lm_descr in words */
+#define LM_DESCR_SIZE_WORDS 11
+
+#ifndef __ASSEMBLER__
+
+enum {
+ LM_MODE_CLIENT = 0,
+ LM_MODE_AP
+};
+
+struct s_lm_descr {
+ uint16_t modes;
+ uint16_t flags;
+ uint32_t buffer_start;
+ uint32_t buffer_end;
+ uint8_t header;
+ uint8_t trailer;
+ uint8_t tx_queues;
+ uint8_t tx_depth;
+ uint8_t privacy;
+ uint8_t rx_keycache;
+ uint8_t tim_size;
+ uint8_t pad1;
+ uint8_t rates[16];
+ uint32_t link;
+ uint16_t mtu;
+};
+
+
+struct s_lm_control {
+ uint16_t flags;
+ uint16_t length;
+ uint32_t handle;
+ uint16_t oid;
+ uint16_t pad;
+ /* uint8_t data[]; */
+};
+
+enum {
+ LM_PRIV_NONE = 0,
+ LM_PRIV_WEP,
+ LM_PRIV_TKIP,
+ LM_PRIV_TKIPMICHAEL,
+ LM_PRIV_CCX_WEPMIC,
+ LM_PRIV_CCX_KPMIC,
+ LM_PRIV_CCX_KP,
+ LM_PRIV_AES_CCMP
+};
+
+enum {
+ LM_DECRYPT_NONE,
+ LM_DECRYPT_OK,
+ LM_DECRYPT_NOKEY,
+ LM_DECRYPT_NOMICHAEL,
+ LM_DECRYPT_NOCKIPMIC,
+ LM_DECRYPT_FAIL_WEP,
+ LM_DECRYPT_FAIL_TKIP,
+ LM_DECRYPT_FAIL_MICHAEL,
+ LM_DECRYPT_FAIL_CKIPKP,
+ LM_DECRYPT_FAIL_CKIPMIC,
+ LM_DECRYPT_FAIL_AESCCMP
+};
+
+struct s_lm_data_out {
+ uint16_t flags;
+ uint16_t length;
+ uint32_t handle;
+ uint16_t aid;
+ uint8_t rts_retries;
+ uint8_t retries;
+ uint8_t aloft[8];
+ uint8_t aloft_ctrl;
+ uint8_t crypt_offset;
+ uint8_t keytype;
+ uint8_t keylen;
+ uint8_t key[16];
+ uint8_t queue;
+ uint8_t backlog;
+ uint16_t durations[4];
+ uint8_t antenna;
+ uint8_t cts;
+ int16_t power;
+ uint8_t pad[2];
+ /*uint8_t data[];*/
+};
+
+#define LM_RCPI_INVALID (0xff)
+
+struct s_lm_data_in {
+ uint16_t flags;
+ uint16_t length;
+ uint16_t frequency;
+ uint8_t antenna;
+ uint8_t rate;
+ uint8_t rcpi;
+ uint8_t sq;
+ uint8_t decrypt;
+ uint8_t rssi_raw;
+ uint32_t clock[2];
+ /*uint8_t data[];*/
+};
+
+union u_lm_data {
+ struct s_lm_data_out out;
+ struct s_lm_data_in in;
+};
+
+enum {
+ LM_OID_SETUP = 0,
+ LM_OID_SCAN = 1,
+ LM_OID_TRAP = 2,
+ LM_OID_EDCF = 3,
+ LM_OID_KEYCACHE = 4,
+ LM_OID_PSM = 6,
+ LM_OID_TXCANCEL = 7,
+ LM_OID_TX = 8,
+ LM_OID_BURST = 9,
+ LM_OID_STATS = 10,
+ LM_OID_LED = 13,
+ LM_OID_TIMER = 15,
+ LM_OID_NAV = 20,
+ LM_OID_PCS = 22,
+ LM_OID_BT_BALANCER = 28,
+ LM_OID_GROUP_ADDRESS_TABLE = 30,
+ LM_OID_ARPTABLE = 31,
+ LM_OID_BT_OPTIONS = 35
+};
+
+enum {
+ LM_FRONTEND_UNKNOWN = 0,
+ LM_FRONTEND_DUETTE3,
+ LM_FRONTEND_DUETTE2,
+ LM_FRONTEND_FRISBEE,
+ LM_FRONTEND_CROSSBOW,
+ LM_FRONTEND_LONGBOW
+};
+
+
+#define INVALID_LPF_BANDWIDTH 0xffff
+#define INVALID_OSC_START_DELAY 0xffff
+
+struct s_lmo_setup {
+ uint16_t flags;
+ uint8_t macaddr[6];
+ uint8_t bssid[6];
+ uint8_t antenna;
+ uint8_t rx_align;
+ uint32_t rx_buffer;
+ uint16_t rx_mtu;
+ uint16_t frontend;
+ uint16_t timeout;
+ uint16_t truncate;
+ uint32_t bratemask;
+ uint8_t sbss_offset;
+ uint8_t mcast_window;
+ uint8_t rx_rssi_threshold;
+ uint8_t rx_ed_threshold;
+ uint32_t ref_clock;
+ uint16_t lpf_bandwidth;
+ uint16_t osc_start_delay;
+};
+
+
+struct s_lmo_scan {
+ uint16_t flags;
+ uint16_t dwell;
+ uint8_t channel[292];
+ uint32_t bratemask;
+ uint8_t aloft[8];
+ uint8_t rssical[8];
+};
+
+
+enum {
+ LM_TRAP_SCAN = 0,
+ LM_TRAP_TIMER,
+ LM_TRAP_BEACON_TX,
+ LM_TRAP_FAA_RADIO_ON,
+ LM_TRAP_FAA_RADIO_OFF,
+ LM_TRAP_RADAR,
+ LM_TRAP_NO_BEACON,
+ LM_TRAP_TBTT,
+ LM_TRAP_SCO_ENTER,
+ LM_TRAP_SCO_EXIT
+};
+
+struct s_lmo_trap {
+ uint16_t event;
+ uint16_t frequency;
+};
+
+struct s_lmo_timer {
+ uint32_t interval;
+};
+
+struct s_lmo_nav {
+ uint32_t period;
+};
+
+
+struct s_lmo_edcf_queue;
+
+struct s_lmo_edcf {
+ uint8_t flags;
+ uint8_t slottime;
+ uint8_t sifs;
+ uint8_t eofpad;
+ struct s_lmo_edcf_queue {
+ uint8_t aifs;
+ uint8_t pad0;
+ uint16_t cwmin;
+ uint16_t cwmax;
+ uint16_t txop;
+ } queues[8];
+ uint8_t mapping[4];
+ uint16_t maxburst;
+ uint16_t round_trip_delay;
+};
+
+struct s_lmo_keycache {
+ uint8_t entry;
+ uint8_t keyid;
+ uint8_t address[6];
+ uint8_t pad[2];
+ uint8_t keytype;
+ uint8_t keylen;
+ uint8_t key[24];
+};
+
+
+struct s_lm_interval;
+
+struct s_lmo_psm {
+ uint16_t flags;
+ uint16_t aid;
+ struct s_lm_interval {
+ uint16_t interval;
+ uint16_t periods;
+ } intervals[4];
+ /* uint16_t pad; */
+ uint8_t beacon_rcpi_skip_max;
+ uint8_t rcpi_delta_threshold;
+ uint8_t nr;
+ uint8_t exclude[1];
+};
+
+#define MC_FILTER_ADDRESS_NUM 4
+
+struct s_lmo_group_address_table {
+ uint16_t filter_enable;
+ uint16_t num_address;
+ uint8_t macaddr_list[MC_FILTER_ADDRESS_NUM][6];
+};
+
+struct s_lmo_txcancel {
+ uint32_t address[1];
+};
+
+
+struct s_lmo_tx {
+ uint8_t flags;
+ uint8_t retries;
+ uint8_t rcpi;
+ uint8_t sq;
+ uint16_t seqctrl;
+ uint8_t antenna;
+ uint8_t pad;
+};
+
+struct s_lmo_burst {
+ uint8_t flags;
+ uint8_t queue;
+ uint8_t backlog;
+ uint8_t pad;
+ uint16_t durations[32];
+};
+
+struct s_lmo_stats {
+ uint32_t valid;
+ uint32_t fcs;
+ uint32_t abort;
+ uint32_t phyabort;
+ uint32_t rts_success;
+ uint32_t rts_fail;
+ uint32_t timestamp;
+ uint32_t time_tx;
+ uint32_t noisefloor;
+ uint32_t sample_noise[8];
+ uint32_t sample_cca;
+ uint32_t sample_tx;
+};
+
+
+struct s_lmo_led {
+ uint16_t flags;
+ uint16_t mask[2];
+ uint16_t delay/*[2]*/;
+};
+
+
+struct s_lmo_bt_balancer {
+ uint16_t prio_thresh;
+ uint16_t acl_thresh;
+};
+
+
+struct s_lmo_arp_table {
+ uint16_t filter_enable;
+ uint32_t ipaddr;
+};
+
+#endif /* __ASSEMBLER__ */
+
+#endif /* __lmac_h__ */
diff --git a/drivers/staging/sxg/sxg.c b/drivers/staging/sxg/sxg.c
index 1e0cfcd7f0f3..b23cbc678345 100644
--- a/drivers/staging/sxg/sxg.c
+++ b/drivers/staging/sxg/sxg.c
@@ -81,43 +81,46 @@
#include "saharadbgdownload.h"
static int sxg_allocate_buffer_memory(struct adapter_t *adapter, u32 Size,
- enum SXG_BUFFER_TYPE BufferType);
-static void sxg_allocate_rcvblock_complete(struct adapter_t *adapter, void *RcvBlock,
- dma_addr_t PhysicalAddress,
- u32 Length);
+ enum sxg_buffer_type BufferType);
+static void sxg_allocate_rcvblock_complete(struct adapter_t *adapter,
+ void *RcvBlock,
+ dma_addr_t PhysicalAddress,
+ u32 Length);
static void sxg_allocate_sgl_buffer_complete(struct adapter_t *adapter,
- struct SXG_SCATTER_GATHER *SxgSgl,
+ struct sxg_scatter_gather *SxgSgl,
dma_addr_t PhysicalAddress,
u32 Length);
static void sxg_mcast_init_crc32(void);
-
-static int sxg_entry_open(p_net_device dev);
-static int sxg_entry_halt(p_net_device dev);
-static int sxg_ioctl(p_net_device dev, struct ifreq *rq, int cmd);
-static int sxg_send_packets(struct sk_buff *skb, p_net_device dev);
+static int sxg_entry_open(struct net_device *dev);
+static int sxg_entry_halt(struct net_device *dev);
+static int sxg_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+static int sxg_send_packets(struct sk_buff *skb, struct net_device *dev);
static int sxg_transmit_packet(struct adapter_t *adapter, struct sk_buff *skb);
-static void sxg_dumb_sgl(struct SCATTER_GATHER_LIST *pSgl, struct SXG_SCATTER_GATHER *SxgSgl);
+static void sxg_dumb_sgl(struct sxg_x64_sgl *pSgl,
+ struct sxg_scatter_gather *SxgSgl);
static void sxg_handle_interrupt(struct adapter_t *adapter);
static int sxg_process_isr(struct adapter_t *adapter, u32 MessageId);
static u32 sxg_process_event_queue(struct adapter_t *adapter, u32 RssId);
static void sxg_complete_slow_send(struct adapter_t *adapter);
-static struct sk_buff *sxg_slow_receive(struct adapter_t *adapter, struct SXG_EVENT *Event);
+static struct sk_buff *sxg_slow_receive(struct adapter_t *adapter,
+ struct sxg_event *Event);
static void sxg_process_rcv_error(struct adapter_t *adapter, u32 ErrorStatus);
static bool sxg_mac_filter(struct adapter_t *adapter,
struct ether_header *EtherHdr, ushort length);
#if SLIC_GET_STATS_ENABLED
-static struct net_device_stats *sxg_get_stats(p_net_device dev);
+static struct net_device_stats *sxg_get_stats(struct net_device *dev);
#endif
+void SxgFreeResources(struct adapter_t *adapter);
+void SxgFreeRcvBlocks(struct adapter_t *adapter);
+
#define XXXTODO 0
-#if XXXTODO
-static int sxg_mac_set_address(p_net_device dev, void *ptr);
-static void sxg_mcast_set_list(p_net_device dev);
-#endif
+static int sxg_mac_set_address(struct net_device *dev, void *ptr);
+static void sxg_mcast_set_list(struct net_device *dev);
static void sxg_adapter_set_hwaddr(struct adapter_t *adapter);
@@ -131,7 +134,8 @@ static int sxg_initialize_link(struct adapter_t *adapter);
static int sxg_phy_init(struct adapter_t *adapter);
static void sxg_link_event(struct adapter_t *adapter);
static enum SXG_LINK_STATE sxg_get_link_state(struct adapter_t *adapter);
-static void sxg_link_state(struct adapter_t *adapter, enum SXG_LINK_STATE LinkState);
+static void sxg_link_state(struct adapter_t *adapter,
+ enum SXG_LINK_STATE LinkState);
static int sxg_write_mdio_reg(struct adapter_t *adapter,
u32 DevAddr, u32 RegAddr, u32 Value);
static int sxg_read_mdio_reg(struct adapter_t *adapter,
@@ -139,13 +143,14 @@ static int sxg_read_mdio_reg(struct adapter_t *adapter,
static unsigned int sxg_first_init = 1;
static char *sxg_banner =
- "Alacritech SLIC Technology(tm) Server and Storage 10Gbe Accelerator (Non-Accelerated)\n";
+ "Alacritech SLIC Technology(tm) Server and Storage \
+ 10Gbe Accelerator (Non-Accelerated)\n";
static int sxg_debug = 1;
static int debug = -1;
-static p_net_device head_netdevice = NULL;
+static struct net_device *head_netdevice = NULL;
-static struct sxgbase_driver_t sxg_global = {
+static struct sxgbase_driver sxg_global = {
.dynamic_intagg = 1,
};
static int intagg_delay = 100;
@@ -154,8 +159,10 @@ static u32 dynamic_intagg = 0;
#define DRV_NAME "sxg"
#define DRV_VERSION "1.0.1"
#define DRV_AUTHOR "Alacritech, Inc. Engineering"
-#define DRV_DESCRIPTION "Alacritech SLIC Techonology(tm) Non-Accelerated 10Gbe Driver"
-#define DRV_COPYRIGHT "Copyright 2000-2008 Alacritech, Inc. All rights reserved."
+#define DRV_DESCRIPTION \
+ "Alacritech SLIC Techonology(tm) Non-Accelerated 10Gbe Driver"
+#define DRV_COPYRIGHT \
+ "Copyright 2000-2008 Alacritech, Inc. All rights reserved."
MODULE_AUTHOR(DRV_AUTHOR);
MODULE_DESCRIPTION(DRV_DESCRIPTION);
@@ -173,12 +180,6 @@ static struct pci_device_id sxg_pci_tbl[] __devinitdata = {
MODULE_DEVICE_TABLE(pci, sxg_pci_tbl);
-/***********************************************************************
-************************************************************************
-************************************************************************
-************************************************************************
-************************************************************************/
-
static inline void sxg_reg32_write(void __iomem *reg, u32 value, bool flush)
{
writel(value, reg);
@@ -225,12 +226,12 @@ static void sxg_dbg_macaddrs(struct adapter_t *adapter)
}
/* SXG Globals */
-static struct SXG_DRIVER SxgDriver;
+static struct sxg_driver SxgDriver;
#ifdef ATKDBG
-static struct sxg_trace_buffer_t LSxgTraceBuffer;
+static struct sxg_trace_buffer LSxgTraceBuffer;
#endif /* ATKDBG */
-static struct sxg_trace_buffer_t *SxgTraceBuffer = NULL;
+static struct sxg_trace_buffer *SxgTraceBuffer = NULL;
/*
* sxg_download_microcode
@@ -244,14 +245,15 @@ static struct sxg_trace_buffer_t *SxgTraceBuffer = NULL;
* Return
* int
*/
-static bool sxg_download_microcode(struct adapter_t *adapter, enum SXG_UCODE_SEL UcodeSel)
+static bool sxg_download_microcode(struct adapter_t *adapter,
+ enum SXG_UCODE_SEL UcodeSel)
{
- struct SXG_HW_REGS *HwRegs = adapter->HwRegs;
+ struct sxg_hw_regs *HwRegs = adapter->HwRegs;
u32 Section;
u32 ThisSectionSize;
u32 *Instruction = NULL;
u32 BaseAddress, AddressOffset, Address;
-/* u32 Failure; */
+ /* u32 Failure; */
u32 ValueRead;
u32 i;
u32 numSections = 0;
@@ -280,10 +282,12 @@ static bool sxg_download_microcode(struct adapter_t *adapter, enum SXG_UCODE_SEL
/* First, reset the card */
WRITE_REG(HwRegs->Reset, 0xDEAD, FLUSH);
- /* Download each section of the microcode as specified in */
- /* its download file. The *download.c file is generated using */
- /* the saharaobjtoc facility which converts the metastep .obj */
- /* file to a .c file which contains a two dimentional array. */
+ /*
+ * Download each section of the microcode as specified in
+ * its download file. The *download.c file is generated using
+ * the saharaobjtoc facility which converts the metastep .obj
+ * file to a .c file which contains a two dimentional array.
+ */
for (Section = 0; Section < numSections; Section++) {
DBG_ERROR("sxg: SECTION # %d\n", Section);
switch (UcodeSel) {
@@ -295,7 +299,8 @@ static bool sxg_download_microcode(struct adapter_t *adapter, enum SXG_UCODE_SEL
break;
}
BaseAddress = sectionStart[Section];
- ThisSectionSize = sectionSize[Section] / 12; /* Size in instructions */
+ /* Size in instructions */
+ ThisSectionSize = sectionSize[Section] / 12;
for (AddressOffset = 0; AddressOffset < ThisSectionSize;
AddressOffset++) {
Address = BaseAddress + AddressOffset;
@@ -311,19 +316,23 @@ static bool sxg_download_microcode(struct adapter_t *adapter, enum SXG_UCODE_SEL
/* Write instruction address with the WRITE bit set */
WRITE_REG(HwRegs->UcodeAddr,
(Address | MICROCODE_ADDRESS_WRITE), FLUSH);
- /* Sahara bug in the ucode download logic - the write to DataLow */
- /* for the next instruction could get corrupted. To avoid this, */
- /* write to DataLow again for this instruction (which may get */
- /* corrupted, but it doesn't matter), then increment the address */
- /* and write the data for the next instruction to DataLow. That */
- /* write should succeed. */
+ /*
+ * Sahara bug in the ucode download logic - the write to DataLow
+ * for the next instruction could get corrupted. To avoid this,
+ * write to DataLow again for this instruction (which may get
+ * corrupted, but it doesn't matter), then increment the address
+ * and write the data for the next instruction to DataLow. That
+ * write should succeed.
+ */
WRITE_REG(HwRegs->UcodeDataLow, *Instruction, TRUE);
/* Advance 3 u32S to start of next instruction */
Instruction += 3;
}
}
- /* Now repeat the entire operation reading the instruction back and */
- /* checking for parity errors */
+ /*
+ * Now repeat the entire operation reading the instruction back and
+ * checking for parity errors
+ */
for (Section = 0; Section < numSections; Section++) {
DBG_ERROR("sxg: check SECTION # %d\n", Section);
switch (UcodeSel) {
@@ -335,7 +344,8 @@ static bool sxg_download_microcode(struct adapter_t *adapter, enum SXG_UCODE_SEL
break;
}
BaseAddress = sectionStart[Section];
- ThisSectionSize = sectionSize[Section] / 12; /* Size in instructions */
+ /* Size in instructions */
+ ThisSectionSize = sectionSize[Section] / 12;
for (AddressOffset = 0; AddressOffset < ThisSectionSize;
AddressOffset++) {
Address = BaseAddress + AddressOffset;
@@ -348,7 +358,7 @@ static bool sxg_download_microcode(struct adapter_t *adapter, enum SXG_UCODE_SEL
DBG_ERROR("sxg: %s PARITY ERROR\n",
__func__);
- return (FALSE); /* Parity error */
+ return FALSE; /* Parity error */
}
ASSERT((ValueRead & MICROCODE_ADDRESS_MASK) == Address);
/* Read the instruction back and compare */
@@ -356,19 +366,19 @@ static bool sxg_download_microcode(struct adapter_t *adapter, enum SXG_UCODE_SEL
if (ValueRead != *Instruction) {
DBG_ERROR("sxg: %s MISCOMPARE LOW\n",
__func__);
- return (FALSE); /* Miscompare */
+ return FALSE; /* Miscompare */
}
READ_REG(HwRegs->UcodeDataMiddle, ValueRead);
if (ValueRead != *(Instruction + 1)) {
DBG_ERROR("sxg: %s MISCOMPARE MIDDLE\n",
__func__);
- return (FALSE); /* Miscompare */
+ return FALSE; /* Miscompare */
}
READ_REG(HwRegs->UcodeDataHigh, ValueRead);
if (ValueRead != *(Instruction + 2)) {
DBG_ERROR("sxg: %s MISCOMPARE HIGH\n",
__func__);
- return (FALSE); /* Miscompare */
+ return FALSE; /* Miscompare */
}
/* Advance 3 u32S to start of next instruction */
Instruction += 3;
@@ -378,8 +388,10 @@ static bool sxg_download_microcode(struct adapter_t *adapter, enum SXG_UCODE_SEL
/* Everything OK, Go. */
WRITE_REG(HwRegs->UcodeAddr, MICROCODE_ADDRESS_GO, FLUSH);
- /* Poll the CardUp register to wait for microcode to initialize */
- /* Give up after 10,000 attemps (500ms). */
+ /*
+ * Poll the CardUp register to wait for microcode to initialize
+ * Give up after 10,000 attemps (500ms).
+ */
for (i = 0; i < 10000; i++) {
udelay(50);
READ_REG(adapter->UcodeRegs[0].CardUp, ValueRead);
@@ -391,11 +403,13 @@ static bool sxg_download_microcode(struct adapter_t *adapter, enum SXG_UCODE_SEL
if (i == 10000) {
DBG_ERROR("sxg: %s TIMEOUT\n", __func__);
- return (FALSE); /* Timeout */
+ return FALSE; /* Timeout */
}
- /* Now write the LoadSync register. This is used to */
- /* synchronize with the card so it can scribble on the memory */
- /* that contained 0xCAFE from the "CardUp" step above */
+ /*
+ * Now write the LoadSync register. This is used to
+ * synchronize with the card so it can scribble on the memory
+ * that contained 0xCAFE from the "CardUp" step above
+ */
if (UcodeSel == SXG_UCODE_SAHARA) {
WRITE_REG(adapter->UcodeRegs[0].LoadSync, 0, FLUSH);
}
@@ -411,18 +425,17 @@ static bool sxg_download_microcode(struct adapter_t *adapter, enum SXG_UCODE_SEL
* sxg_allocate_resources - Allocate memory and locks
*
* Arguments -
- * adapter - A pointer to our adapter structure
+ * adapter - A pointer to our adapter structure
*
- * Return
- * int
+ * Return - int
*/
static int sxg_allocate_resources(struct adapter_t *adapter)
{
int status;
u32 i;
u32 RssIds, IsrCount;
-/* struct SXG_XMT_RING *XmtRing; */
-/* struct SXG_RCV_RING *RcvRing; */
+ /* struct sxg_xmt_ring *XmtRing; */
+ /* struct sxg_rcv_ring *RcvRing; */
DBG_ERROR("%s ENTER\n", __func__);
@@ -451,57 +464,64 @@ static int sxg_allocate_resources(struct adapter_t *adapter)
InitializeListHead(&adapter->FreeSglBuffers);
InitializeListHead(&adapter->AllSglBuffers);
- /* Mark these basic allocations done. This flags essentially */
- /* tells the SxgFreeResources routine that it can grab spinlocks */
- /* and reference listheads. */
+ /*
+ * Mark these basic allocations done. This flags essentially
+ * tells the SxgFreeResources routine that it can grab spinlocks
+ * and reference listheads.
+ */
adapter->BasicAllocations = TRUE;
- /* Main allocation loop. Start with the maximum supported by */
- /* the microcode and back off if memory allocation */
- /* fails. If we hit a minimum, fail. */
+ /*
+ * Main allocation loop. Start with the maximum supported by
+ * the microcode and back off if memory allocation
+ * fails. If we hit a minimum, fail.
+ */
for (;;) {
DBG_ERROR("%s Allocate XmtRings size[%x]\n", __func__,
- (unsigned int)(sizeof(struct SXG_XMT_RING) * 1));
+ (unsigned int)(sizeof(struct sxg_xmt_ring) * 1));
- /* Start with big items first - receive and transmit rings. At the moment */
- /* I'm going to keep the ring size fixed and adjust the number of */
- /* TCBs if we fail. Later we might consider reducing the ring size as well.. */
+ /*
+ * Start with big items first - receive and transmit rings.
+ * At the moment I'm going to keep the ring size fixed and
+ * adjust the TCBs if we fail. Later we might
+ * consider reducing the ring size as well..
+ */
adapter->XmtRings = pci_alloc_consistent(adapter->pcidev,
- sizeof(struct SXG_XMT_RING) *
- 1,
- &adapter->PXmtRings);
+ sizeof(struct sxg_xmt_ring) *
+ 1,
+ &adapter->PXmtRings);
DBG_ERROR("%s XmtRings[%p]\n", __func__, adapter->XmtRings);
if (!adapter->XmtRings) {
goto per_tcb_allocation_failed;
}
- memset(adapter->XmtRings, 0, sizeof(struct SXG_XMT_RING) * 1);
+ memset(adapter->XmtRings, 0, sizeof(struct sxg_xmt_ring) * 1);
DBG_ERROR("%s Allocate RcvRings size[%x]\n", __func__,
- (unsigned int)(sizeof(struct SXG_RCV_RING) * 1));
+ (unsigned int)(sizeof(struct sxg_rcv_ring) * 1));
adapter->RcvRings =
pci_alloc_consistent(adapter->pcidev,
- sizeof(struct SXG_RCV_RING) * 1,
+ sizeof(struct sxg_rcv_ring) * 1,
&adapter->PRcvRings);
DBG_ERROR("%s RcvRings[%p]\n", __func__, adapter->RcvRings);
if (!adapter->RcvRings) {
goto per_tcb_allocation_failed;
}
- memset(adapter->RcvRings, 0, sizeof(struct SXG_RCV_RING) * 1);
+ memset(adapter->RcvRings, 0, sizeof(struct sxg_rcv_ring) * 1);
break;
per_tcb_allocation_failed:
/* an allocation failed. Free any successful allocations. */
if (adapter->XmtRings) {
pci_free_consistent(adapter->pcidev,
- sizeof(struct SXG_XMT_RING) * 4096,
+ sizeof(struct sxg_xmt_ring) * 1,
adapter->XmtRings,
adapter->PXmtRings);
adapter->XmtRings = NULL;
}
if (adapter->RcvRings) {
pci_free_consistent(adapter->pcidev,
- sizeof(struct SXG_RCV_RING) * 4096,
+ sizeof(struct sxg_rcv_ring) * 1,
adapter->RcvRings,
adapter->PRcvRings);
adapter->RcvRings = NULL;
@@ -515,22 +535,26 @@ static int sxg_allocate_resources(struct adapter_t *adapter)
SXG_INITIALIZE_RING(adapter->XmtRingZeroInfo, SXG_XMT_RING_SIZE);
/* Sanity check receive data structure format */
- ASSERT((adapter->ReceiveBufferSize == SXG_RCV_DATA_BUFFER_SIZE) ||
- (adapter->ReceiveBufferSize == SXG_RCV_JUMBO_BUFFER_SIZE));
- ASSERT(sizeof(struct SXG_RCV_DESCRIPTOR_BLOCK) ==
+ /* ASSERT((adapter->ReceiveBufferSize == SXG_RCV_DATA_BUFFER_SIZE) ||
+ (adapter->ReceiveBufferSize == SXG_RCV_JUMBO_BUFFER_SIZE)); */
+ ASSERT(sizeof(struct sxg_rcv_descriptor_block) ==
SXG_RCV_DESCRIPTOR_BLOCK_SIZE);
- /* Allocate receive data buffers. We allocate a block of buffers and */
- /* a corresponding descriptor block at once. See sxghw.h:SXG_RCV_BLOCK */
+ /*
+ * Allocate receive data buffers. We allocate a block of buffers and
+ * a corresponding descriptor block at once. See sxghw.h:SXG_RCV_BLOCK
+ */
for (i = 0; i < SXG_INITIAL_RCV_DATA_BUFFERS;
- i += SXG_RCV_DESCRIPTORS_PER_BLOCK) {
- sxg_allocate_buffer_memory(adapter,
- SXG_RCV_BLOCK_SIZE(adapter->
- ReceiveBufferSize),
+ i += SXG_RCV_DESCRIPTORS_PER_BLOCK) {
+ sxg_allocate_buffer_memory(adapter,
+ SXG_RCV_BLOCK_SIZE(SXG_RCV_DATA_HDR_SIZE),
SXG_BUFFER_TYPE_RCV);
}
- /* NBL resource allocation can fail in the 'AllocateComplete' routine, which */
- /* doesn't return status. Make sure we got the number of buffers we requested */
+ /*
+ * NBL resource allocation can fail in the 'AllocateComplete' routine,
+ * which doesn't return status. Make sure we got the number of buffers
+ * we requested
+ */
if (adapter->FreeRcvBufferCount < SXG_INITIAL_RCV_DATA_BUFFERS) {
SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "XAResF6",
adapter, adapter->FreeRcvBufferCount, SXG_MAX_ENTRIES,
@@ -539,29 +563,31 @@ static int sxg_allocate_resources(struct adapter_t *adapter)
}
DBG_ERROR("%s Allocate EventRings size[%x]\n", __func__,
- (unsigned int)(sizeof(struct SXG_EVENT_RING) * RssIds));
+ (unsigned int)(sizeof(struct sxg_event_ring) * RssIds));
/* Allocate event queues. */
adapter->EventRings = pci_alloc_consistent(adapter->pcidev,
- sizeof(struct SXG_EVENT_RING) *
- RssIds,
- &adapter->PEventRings);
+ sizeof(struct sxg_event_ring) *
+ RssIds,
+ &adapter->PEventRings);
if (!adapter->EventRings) {
- /* Caller will call SxgFreeAdapter to clean up above allocations */
+ /* Caller will call SxgFreeAdapter to clean up above
+ * allocations */
SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "XAResF8",
adapter, SXG_MAX_ENTRIES, 0, 0);
status = STATUS_RESOURCES;
goto per_tcb_allocation_failed;
}
- memset(adapter->EventRings, 0, sizeof(struct SXG_EVENT_RING) * RssIds);
+ memset(adapter->EventRings, 0, sizeof(struct sxg_event_ring) * RssIds);
DBG_ERROR("%s Allocate ISR size[%x]\n", __func__, IsrCount);
/* Allocate ISR */
adapter->Isr = pci_alloc_consistent(adapter->pcidev,
IsrCount, &adapter->PIsr);
if (!adapter->Isr) {
- /* Caller will call SxgFreeAdapter to clean up above allocations */
+ /* Caller will call SxgFreeAdapter to clean up above
+ * allocations */
SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "XAResF9",
adapter, SXG_MAX_ENTRIES, 0, 0);
status = STATUS_RESOURCES;
@@ -599,7 +625,6 @@ static int sxg_allocate_resources(struct adapter_t *adapter)
*
* Arguments -
* pcidev - A pointer to our adapter structure
- *
*/
static void sxg_config_pci(struct pci_dev *pcidev)
{
@@ -609,12 +634,19 @@ static void sxg_config_pci(struct pci_dev *pcidev)
pci_read_config_word(pcidev, PCI_COMMAND, &pci_command);
DBG_ERROR("sxg: %s PCI command[%4.4x]\n", __func__, pci_command);
/* Set the command register */
- new_command = pci_command | (PCI_COMMAND_MEMORY | /* Memory Space Enable */
- PCI_COMMAND_MASTER | /* Bus master enable */
- PCI_COMMAND_INVALIDATE | /* Memory write and invalidate */
- PCI_COMMAND_PARITY | /* Parity error response */
- PCI_COMMAND_SERR | /* System ERR */
- PCI_COMMAND_FAST_BACK); /* Fast back-to-back */
+ new_command = pci_command | (
+ /* Memory Space Enable */
+ PCI_COMMAND_MEMORY |
+ /* Bus master enable */
+ PCI_COMMAND_MASTER |
+ /* Memory write and invalidate */
+ PCI_COMMAND_INVALIDATE |
+ /* Parity error response */
+ PCI_COMMAND_PARITY |
+ /* System ERR */
+ PCI_COMMAND_SERR |
+ /* Fast back-to-back */
+ PCI_COMMAND_FAST_BACK);
if (pci_command != new_command) {
DBG_ERROR("%s -- Updating PCI COMMAND register %4.4x->%4.4x.\n",
__func__, pci_command, new_command);
@@ -622,6 +654,73 @@ static void sxg_config_pci(struct pci_dev *pcidev)
}
}
+/*
+ * sxg_read_config
+ * @adapter : Pointer to the adapter structure for the card
+ * This function will read the configuration data from EEPROM/FLASH
+ */
+static inline int sxg_read_config(struct adapter_t *adapter)
+{
+ /* struct sxg_config data; */
+ struct sw_cfg_data *data;
+ dma_addr_t p_addr;
+ unsigned long status;
+ unsigned long i;
+
+ data = pci_alloc_consistent(adapter->pcidev,
+ sizeof(struct sw_cfg_data), &p_addr);
+ if(!data) {
+ /*
+ * We cant get even this much memory. Raise a hell
+ * Get out of here
+ */
+ printk(KERN_ERR"%s : Could not allocate memory for reading \
+ EEPROM\n", __FUNCTION__);
+ return -ENOMEM;
+ }
+
+ WRITE_REG(adapter->UcodeRegs[0].ConfigStat, SXG_CFG_TIMEOUT, TRUE);
+
+ WRITE_REG64(adapter, adapter->UcodeRegs[0].Config, p_addr, 0);
+ for(i=0; i<1000; i++) {
+ READ_REG(adapter->UcodeRegs[0].ConfigStat, status);
+ if (status != SXG_CFG_TIMEOUT)
+ break;
+ mdelay(1); /* Do we really need this */
+ }
+
+ switch(status) {
+ /* Config read from EEPROM succeeded */
+ case SXG_CFG_LOAD_EEPROM:
+ /* Config read from Flash succeeded */
+ case SXG_CFG_LOAD_FLASH:
+ /* Copy the MAC address to adapter structure */
+ /* TODO: We are not doing the remaining part : FRU,
+ * etc
+ */
+ memcpy(adapter->macaddr, data->MacAddr[0].MacAddr,
+ sizeof(struct sxg_config_mac));
+ break;
+ case SXG_CFG_TIMEOUT:
+ case SXG_CFG_LOAD_INVALID:
+ case SXG_CFG_LOAD_ERROR:
+ default: /* Fix default handler later */
+ printk(KERN_WARNING"%s : We could not read the config \
+ word. Status = %ld\n", __FUNCTION__, status);
+ break;
+ }
+ pci_free_consistent(adapter->pcidev, sizeof(struct sw_cfg_data), data,
+ p_addr);
+ if (adapter->netdev) {
+ memcpy(adapter->netdev->dev_addr, adapter->currmacaddr, 6);
+ memcpy(adapter->netdev->perm_addr, adapter->currmacaddr, 6);
+ }
+ printk("LINSYS : These are the new MAC address\n");
+ sxg_dbg_macaddrs(adapter);
+
+ return status;
+}
+
static int sxg_entry_probe(struct pci_dev *pcidev,
const struct pci_device_id *pci_tbl_entry)
{
@@ -710,9 +809,9 @@ static int sxg_entry_probe(struct pci_dev *pcidev,
goto err_out_free_mmio_region;
}
- DBG_ERROR
- ("sxg: %s found Alacritech SXG PCI, MMIO at %p, start[%lx] len[%lx], IRQ %d.\n",
- __func__, memmapped_ioaddr, mmio_start, mmio_len, pcidev->irq);
+ DBG_ERROR("sxg: %s found Alacritech SXG PCI, MMIO at %p, start[%lx] \
+ len[%lx], IRQ %d.\n", __func__, memmapped_ioaddr, mmio_start,
+ mmio_len, pcidev->irq);
adapter->HwRegs = (void *)memmapped_ioaddr;
adapter->base_addr = memmapped_ioaddr;
@@ -739,8 +838,10 @@ static int sxg_entry_probe(struct pci_dev *pcidev,
adapter->UcodeRegs = (void *)memmapped_ioaddr;
adapter->State = SXG_STATE_INITIALIZING;
- /* Maintain a list of all adapters anchored by */
- /* the global SxgDriver structure. */
+ /*
+ * Maintain a list of all adapters anchored by
+ * the global SxgDriver structure.
+ */
adapter->Next = SxgDriver.Adapters;
SxgDriver.Adapters = adapter;
adapter->AdapterID = ++SxgDriver.AdapterID;
@@ -758,10 +859,12 @@ static int sxg_entry_probe(struct pci_dev *pcidev,
adapter->ReceiveBufferSize = SXG_RCV_DATA_BUFFER_SIZE;
}
-/* status = SXG_READ_EEPROM(adapter); */
-/* if (!status) { */
-/* goto sxg_init_bad; */
-/* } */
+ /*
+ * status = SXG_READ_EEPROM(adapter);
+ * if (!status) {
+ * goto sxg_init_bad;
+ * }
+ */
DBG_ERROR("sxg: %s ENTER sxg_config_pci\n", __func__);
sxg_config_pci(pcidev);
@@ -774,16 +877,13 @@ static int sxg_entry_probe(struct pci_dev *pcidev,
adapter->vendid = pci_tbl_entry->vendor;
adapter->devid = pci_tbl_entry->device;
adapter->subsysid = pci_tbl_entry->subdevice;
- adapter->busnumber = pcidev->bus->number;
adapter->slotnumber = ((pcidev->devfn >> 3) & 0x1F);
adapter->functionnumber = (pcidev->devfn & 0x7);
adapter->memorylength = pci_resource_len(pcidev, 0);
adapter->irq = pcidev->irq;
adapter->next_netdevice = head_netdevice;
head_netdevice = netdev;
-/* adapter->chipid = chip_idx; */
adapter->port = 0; /*adapter->functionnumber; */
- adapter->cardindex = adapter->port;
/* Allocate memory and other resources */
DBG_ERROR("sxg: %s ENTER sxg_allocate_resources\n", __func__);
@@ -798,6 +898,7 @@ static int sxg_entry_probe(struct pci_dev *pcidev,
if (sxg_download_microcode(adapter, SXG_UCODE_SAHARA)) {
DBG_ERROR("sxg: %s ENTER sxg_adapter_set_hwaddr\n",
__func__);
+ sxg_read_config(adapter);
sxg_adapter_set_hwaddr(adapter);
} else {
adapter->state = ADAPT_FAIL;
@@ -816,11 +917,11 @@ static int sxg_entry_probe(struct pci_dev *pcidev,
#if SLIC_GET_STATS_ENABLED
netdev->get_stats = sxg_get_stats;
#endif
- netdev->set_multicast_list = sxg_mcast_set_list;
#endif
+ netdev->set_multicast_list = sxg_mcast_set_list;
strcpy(netdev->name, "eth%d");
-/* strcpy(netdev->name, pci_name(pcidev)); */
+ /* strcpy(netdev->name, pci_name(pcidev)); */
if ((err = register_netdev(netdev))) {
DBG_ERROR("Cannot register net device, aborting. %s\n",
netdev->name);
@@ -828,14 +929,15 @@ static int sxg_entry_probe(struct pci_dev *pcidev,
}
DBG_ERROR
- ("sxg: %s addr 0x%lx, irq %d, MAC addr %02X:%02X:%02X:%02X:%02X:%02X\n",
+ ("sxg: %s addr 0x%lx, irq %d, MAC addr \
+ %02X:%02X:%02X:%02X:%02X:%02X\n",
netdev->name, netdev->base_addr, pcidev->irq, netdev->dev_addr[0],
netdev->dev_addr[1], netdev->dev_addr[2], netdev->dev_addr[3],
netdev->dev_addr[4], netdev->dev_addr[5]);
-/*sxg_init_bad: */
+ /* sxg_init_bad: */
ASSERT(status == FALSE);
-/* sxg_free_adapter(adapter); */
+ /* sxg_free_adapter(adapter); */
DBG_ERROR("sxg: %s EXIT status[%x] jiffies[%lx] cpu %d\n", __func__,
status, jiffies, smp_processor_id());
@@ -855,10 +957,8 @@ static int sxg_entry_probe(struct pci_dev *pcidev,
return -ENODEV;
}
-/***********************************************************************
- * LINE BASE Interrupt routines..
- ***********************************************************************/
/*
+ * LINE BASE Interrupt routines..
*
* sxg_disable_interrupt
*
@@ -878,9 +978,7 @@ static void sxg_disable_interrupt(struct adapter_t *adapter)
/* For now, RSS is disabled with line based interrupts */
ASSERT(adapter->RssEnabled == FALSE);
ASSERT(adapter->MsiEnabled == FALSE);
- /* */
/* Turn off interrupts by writing to the icr register. */
- /* */
WRITE_REG(adapter->UcodeRegs[0].Icr, SXG_ICR(0, SXG_ICR_DISABLE), TRUE);
adapter->InterruptsEnabled = 0;
@@ -890,7 +988,6 @@ static void sxg_disable_interrupt(struct adapter_t *adapter)
}
/*
- *
* sxg_enable_interrupt
*
* EnableInterrupt Handler
@@ -909,9 +1006,7 @@ static void sxg_enable_interrupt(struct adapter_t *adapter)
/* For now, RSS is disabled with line based interrupts */
ASSERT(adapter->RssEnabled == FALSE);
ASSERT(adapter->MsiEnabled == FALSE);
- /* */
/* Turn on interrupts by writing to the icr register. */
- /* */
WRITE_REG(adapter->UcodeRegs[0].Icr, SXG_ICR(0, SXG_ICR_ENABLE), TRUE);
adapter->InterruptsEnabled = 1;
@@ -921,50 +1016,53 @@ static void sxg_enable_interrupt(struct adapter_t *adapter)
}
/*
- *
* sxg_isr - Process an line-based interrupt
*
* Arguments:
- * Context - Our adapter structure
+ * Context - Our adapter structure
* QueueDefault - Output parameter to queue to default CPU
- * TargetCpus - Output bitmap to schedule DPC's
+ * TargetCpus - Output bitmap to schedule DPC's
*
- * Return Value:
- * TRUE if our interrupt
+ * Return Value: TRUE if our interrupt
*/
static irqreturn_t sxg_isr(int irq, void *dev_id)
{
- p_net_device dev = (p_net_device) dev_id;
+ struct net_device *dev = (struct net_device *) dev_id;
struct adapter_t *adapter = (struct adapter_t *) netdev_priv(dev);
-/* u32 CpuMask = 0, i; */
+ /* u32 CpuMask = 0, i; */
adapter->Stats.NumInts++;
if (adapter->Isr[0] == 0) {
- /* The SLIC driver used to experience a number of spurious interrupts */
- /* due to the delay associated with the masking of the interrupt */
- /* (we'd bounce back in here). If we see that again with Sahara, */
- /* add a READ_REG of the Icr register after the WRITE_REG below. */
+ /*
+ * The SLIC driver used to experience a number of spurious
+ * interrupts due to the delay associated with the masking of
+ * the interrupt (we'd bounce back in here). If we see that
+ * again with Sahara,add a READ_REG of the Icr register after
+ * the WRITE_REG below.
+ */
adapter->Stats.FalseInts++;
return IRQ_NONE;
}
- /* */
- /* Move the Isr contents and clear the value in */
- /* shared memory, and mask interrupts */
- /* */
+ /*
+ * Move the Isr contents and clear the value in
+ * shared memory, and mask interrupts
+ */
adapter->IsrCopy[0] = adapter->Isr[0];
adapter->Isr[0] = 0;
WRITE_REG(adapter->UcodeRegs[0].Icr, SXG_ICR(0, SXG_ICR_MASK), TRUE);
-/* ASSERT(adapter->IsrDpcsPending == 0); */
+ /* ASSERT(adapter->IsrDpcsPending == 0); */
#if XXXTODO /* RSS Stuff */
- /* If RSS is enabled and the ISR specifies */
- /* SXG_ISR_EVENT, then schedule DPC's */
- /* based on event queues. */
+ /*
+ * If RSS is enabled and the ISR specifies SXG_ISR_EVENT, then
+ * schedule DPC's based on event queues.
+ */
if (adapter->RssEnabled && (adapter->IsrCopy[0] & SXG_ISR_EVENT)) {
for (i = 0;
i < adapter->RssSystemInfo->ProcessorInfo.RssCpuCount;
i++) {
- struct XG_EVENT_RING *EventRing = &adapter->EventRings[i];
- struct SXG_EVENT *Event =
+ struct sxg_event_ring *EventRing =
+ &adapter->EventRings[i];
+ struct sxg_event *Event =
&EventRing->Ring[adapter->NextEvent[i]];
unsigned char Cpu =
adapter->RssSystemInfo->RssIdToCpu[i];
@@ -974,8 +1072,10 @@ static irqreturn_t sxg_isr(int irq, void *dev_id)
}
}
}
- /* Now, either schedule the CPUs specified by the CpuMask, */
- /* or queue default */
+ /*
+ * Now, either schedule the CPUs specified by the CpuMask,
+ * or queue default
+ */
if (CpuMask) {
*QueueDefault = FALSE;
} else {
@@ -984,20 +1084,20 @@ static irqreturn_t sxg_isr(int irq, void *dev_id)
}
*TargetCpus = CpuMask;
#endif
- /* */
/* There are no DPCs in Linux, so call the handler now */
- /* */
sxg_handle_interrupt(adapter);
return IRQ_HANDLED;
}
+int debug_inthandler = 0;
+
static void sxg_handle_interrupt(struct adapter_t *adapter)
{
-/* unsigned char RssId = 0; */
+ /* unsigned char RssId = 0; */
u32 NewIsr;
- if (adapter->Stats.RcvNoBuffer < 5) {
+ if (++debug_inthandler < 20) {
DBG_ERROR("Enter sxg_handle_interrupt ISR[%x]\n",
adapter->IsrCopy[0]);
}
@@ -1007,7 +1107,6 @@ static void sxg_handle_interrupt(struct adapter_t *adapter)
ASSERT(adapter->RssEnabled == FALSE);
ASSERT(adapter->MsiEnabled == FALSE);
ASSERT(adapter->IsrCopy[0]);
-/*/////////////////////////// */
/* Always process the event queue. */
sxg_process_event_queue(adapter,
@@ -1022,18 +1121,14 @@ static void sxg_handle_interrupt(struct adapter_t *adapter)
return;
}
#endif
- /* */
/* Last (or only) DPC processes the ISR and clears the interrupt. */
- /* */
NewIsr = sxg_process_isr(adapter, 0);
- /* */
/* Reenable interrupts */
- /* */
adapter->IsrCopy[0] = 0;
SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "ClearIsr",
adapter, NewIsr, 0, 0);
- if (adapter->Stats.RcvNoBuffer < 5) {
+ if (debug_inthandler < 20) {
DBG_ERROR
("Exit sxg_handle_interrupt2 after enabling interrupt\n");
}
@@ -1045,7 +1140,6 @@ static void sxg_handle_interrupt(struct adapter_t *adapter)
}
/*
- *
* sxg_process_isr - Process an interrupt. Called from the line-based and
* message based interrupt DPC routines
*
@@ -1064,6 +1158,7 @@ static int sxg_process_isr(struct adapter_t *adapter, u32 MessageId)
SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "ProcIsr",
adapter, Isr, 0, 0);
+ DBG_ERROR("%s: Entering with %d ISR value\n", __FUNCTION__, Isr);
/* Error */
if (Isr & SXG_ISR_ERR) {
if (Isr & SXG_ISR_PDQF) {
@@ -1072,12 +1167,14 @@ static int sxg_process_isr(struct adapter_t *adapter, u32 MessageId)
}
/* No host buffer */
if (Isr & SXG_ISR_RMISS) {
- /* There is a bunch of code in the SLIC driver which */
- /* attempts to process more receive events per DPC */
- /* if we start to fall behind. We'll probably */
- /* need to do something similar here, but hold */
- /* off for now. I don't want to make the code more */
- /* complicated than strictly needed. */
+ /*
+ * There is a bunch of code in the SLIC driver which
+ * attempts to process more receive events per DPC
+ * if we start to fall behind. We'll probablyd
+ * need to do something similar here, but hold
+ * off for now. I don't want to make the code more
+ * complicated than strictly needed.
+ */
adapter->Stats.RcvNoBuffer++;
if (adapter->Stats.RcvNoBuffer < 5) {
DBG_ERROR("%s: SXG_ISR_ERR RMISS!!\n",
@@ -1086,10 +1183,12 @@ static int sxg_process_isr(struct adapter_t *adapter, u32 MessageId)
}
/* Card crash */
if (Isr & SXG_ISR_DEAD) {
- /* Set aside the crash info and set the adapter state to RESET */
- adapter->CrashCpu =
- (unsigned char)((Isr & SXG_ISR_CPU) >>
- SXG_ISR_CPU_SHIFT);
+ /*
+ * Set aside the crash info and set the adapter state
+ * to RESET
+ */
+ adapter->CrashCpu = (unsigned char)
+ ((Isr & SXG_ISR_CPU) >> SXG_ISR_CPU_SHIFT);
adapter->CrashLocation = (ushort) (Isr & SXG_ISR_CRASH);
adapter->Dead = TRUE;
DBG_ERROR("%s: ISR_DEAD %x, CPU: %d\n", __func__,
@@ -1097,10 +1196,12 @@ static int sxg_process_isr(struct adapter_t *adapter, u32 MessageId)
}
/* Event ring full */
if (Isr & SXG_ISR_ERFULL) {
- /* Same issue as RMISS, really. This means the */
- /* host is falling behind the card. Need to increase */
- /* event ring size, process more events per interrupt, */
- /* and/or reduce/remove interrupt aggregation. */
+ /*
+ * Same issue as RMISS, really. This means the
+ * host is falling behind the card. Need to increase
+ * event ring size, process more events per interrupt,
+ * and/or reduce/remove interrupt aggregation.
+ */
adapter->Stats.EventRingFull++;
DBG_ERROR("%s: SXG_ISR_ERR EVENT RING FULL!!\n",
__func__);
@@ -1118,7 +1219,8 @@ static int sxg_process_isr(struct adapter_t *adapter, u32 MessageId)
}
/* Dump */
if (Isr & SXG_ISR_UPC) {
- ASSERT(adapter->DumpCmdRunning); /* Maybe change when debug is added.. */
+ /* Maybe change when debug is added.. */
+ ASSERT(adapter->DumpCmdRunning);
adapter->DumpCmdRunning = FALSE;
}
/* Link event */
@@ -1127,9 +1229,11 @@ static int sxg_process_isr(struct adapter_t *adapter, u32 MessageId)
}
/* Debug - breakpoint hit */
if (Isr & SXG_ISR_BREAK) {
- /* At the moment AGDB isn't written to support interactive */
- /* debug sessions. When it is, this interrupt will be used */
- /* to signal AGDB that it has hit a breakpoint. For now, ASSERT. */
+ /*
+ * At the moment AGDB isn't written to support interactive
+ * debug sessions. When it is, this interrupt will be used to
+ * signal AGDB that it has hit a breakpoint. For now, ASSERT.
+ */
ASSERT(0);
}
/* Heartbeat response */
@@ -1143,7 +1247,6 @@ static int sxg_process_isr(struct adapter_t *adapter, u32 MessageId)
}
/*
- *
* sxg_process_event_queue - Process our event queue
*
* Arguments:
@@ -1155,8 +1258,8 @@ static int sxg_process_isr(struct adapter_t *adapter, u32 MessageId)
*/
static u32 sxg_process_event_queue(struct adapter_t *adapter, u32 RssId)
{
- struct SXG_EVENT_RING *EventRing = &adapter->EventRings[RssId];
- struct SXG_EVENT *Event = &EventRing->Ring[adapter->NextEvent[RssId]];
+ struct sxg_event_ring *EventRing = &adapter->EventRings[RssId];
+ struct sxg_event *Event = &EventRing->Ring[adapter->NextEvent[RssId]];
u32 EventsProcessed = 0, Batches = 0;
u32 num_skbs = 0;
struct sk_buff *skb;
@@ -1164,7 +1267,7 @@ static u32 sxg_process_event_queue(struct adapter_t *adapter, u32 RssId)
struct sk_buff *prev_skb = NULL;
struct sk_buff *IndicationList[SXG_RCV_ARRAYSIZE];
u32 Index;
- struct SXG_RCV_DATA_BUFFER_HDR *RcvDataBufferHdr;
+ struct sxg_rcv_data_buffer_hdr *RcvDataBufferHdr;
#endif
u32 ReturnStatus = 0;
@@ -1172,25 +1275,28 @@ static u32 sxg_process_event_queue(struct adapter_t *adapter, u32 RssId)
(adapter->State == SXG_STATE_PAUSING) ||
(adapter->State == SXG_STATE_PAUSED) ||
(adapter->State == SXG_STATE_HALTING));
- /* We may still have unprocessed events on the queue if */
- /* the card crashed. Don't process them. */
+ /*
+ * We may still have unprocessed events on the queue if
+ * the card crashed. Don't process them.
+ */
if (adapter->Dead) {
return (0);
}
- /* In theory there should only be a single processor that */
- /* accesses this queue, and only at interrupt-DPC time. So */
- /* we shouldn't need a lock for any of this. */
+ /*
+ * In theory there should only be a single processor that
+ * accesses this queue, and only at interrupt-DPC time. So/
+ * we shouldn't need a lock for any of this.
+ */
while (Event->Status & EVENT_STATUS_VALID) {
SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "Event",
Event, Event->Code, Event->Status,
adapter->NextEvent);
switch (Event->Code) {
case EVENT_CODE_BUFFERS:
- ASSERT(!(Event->CommandIndex & 0xFF00)); /* SXG_RING_INFO Head & Tail == unsigned char */
- /* */
+ /* struct sxg_ring_info Head & Tail == unsigned char */
+ ASSERT(!(Event->CommandIndex & 0xFF00));
sxg_complete_descriptor_blocks(adapter,
Event->CommandIndex);
- /* */
break;
case EVENT_CODE_SLOWRCV:
--adapter->RcvBuffersOnCard;
@@ -1200,19 +1306,21 @@ static u32 sxg_process_event_queue(struct adapter_t *adapter, u32 RssId)
/* Add it to our indication list */
SXG_ADD_RCV_PACKET(adapter, skb, prev_skb,
IndicationList, num_skbs);
- /* In Linux, we just pass up each skb to the protocol above at this point, */
- /* there is no capability of an indication list. */
+ /*
+ * Linux, we just pass up each skb to the
+ * protocol above at this point, there is no
+ * capability of an indication list.
+ */
#else
-/* CHECK skb_pull(skb, INIC_RCVBUF_HEADSIZE); */
- rx_bytes = Event->Length; /* (rcvbuf->length & IRHDDR_FLEN_MSK); */
- skb_put(skb, rx_bytes);
+ /* CHECK skb_pull(skb, INIC_RCVBUF_HEADSIZE); */
+ /* (rcvbuf->length & IRHDDR_FLEN_MSK); */
+ rx_bytes = Event->Length;
adapter->stats.rx_packets++;
adapter->stats.rx_bytes += rx_bytes;
#if SXG_OFFLOAD_IP_CHECKSUM
skb->ip_summed = CHECKSUM_UNNECESSARY;
#endif
skb->dev = adapter->netdev;
- skb->protocol = eth_type_trans(skb, skb->dev);
netif_rx(skb);
#endif
}
@@ -1220,31 +1328,38 @@ static u32 sxg_process_event_queue(struct adapter_t *adapter, u32 RssId)
default:
DBG_ERROR("%s: ERROR Invalid EventCode %d\n",
__func__, Event->Code);
-/* ASSERT(0); */
+ /* ASSERT(0); */
}
- /* See if we need to restock card receive buffers. */
- /* There are two things to note here: */
- /* First - This test is not SMP safe. The */
- /* adapter->BuffersOnCard field is protected via atomic interlocked calls, but */
- /* we do not protect it with respect to these tests. The only way to do that */
- /* is with a lock, and I don't want to grab a lock every time we adjust the */
- /* BuffersOnCard count. Instead, we allow the buffer replenishment to be off */
- /* once in a while. The worst that can happen is the card is given one */
- /* more-or-less descriptor block than the arbitrary value we've chosen. */
- /* No big deal */
- /* In short DO NOT ADD A LOCK HERE, OR WHERE RcvBuffersOnCard is adjusted. */
- /* Second - We expect this test to rarely evaluate to true. We attempt to */
- /* refill descriptor blocks as they are returned to us */
- /* (sxg_complete_descriptor_blocks), so The only time this should evaluate */
- /* to true is when sxg_complete_descriptor_blocks failed to allocate */
- /* receive buffers. */
+ /*
+ * See if we need to restock card receive buffers.
+ * There are two things to note here:
+ * First - This test is not SMP safe. The
+ * adapter->BuffersOnCard field is protected via atomic
+ * interlocked calls, but we do not protect it with respect
+ * to these tests. The only way to do that is with a lock,
+ * and I don't want to grab a lock every time we adjust the
+ * BuffersOnCard count. Instead, we allow the buffer
+ * replenishment to be off once in a while. The worst that
+ * can happen is the card is given on more-or-less descriptor
+ * block than the arbitrary value we've chosen. No big deal
+ * In short DO NOT ADD A LOCK HERE, OR WHERE RcvBuffersOnCard
+ * is adjusted.
+ * Second - We expect this test to rarely
+ * evaluate to true. We attempt to refill descriptor blocks
+ * as they are returned to us (sxg_complete_descriptor_blocks)
+ * so The only time this should evaluate to true is when
+ * sxg_complete_descriptor_blocks failed to allocate
+ * receive buffers.
+ */
if (adapter->RcvBuffersOnCard < SXG_RCV_DATA_BUFFERS) {
sxg_stock_rcv_buffers(adapter);
}
- /* It's more efficient to just set this to zero. */
- /* But clearing the top bit saves potential debug info... */
+ /*
+ * It's more efficient to just set this to zero.
+ * But clearing the top bit saves potential debug info...
+ */
Event->Status &= ~EVENT_STATUS_VALID;
- /* Advanct to the next event */
+ /* Advance to the next event */
SXG_ADVANCE_INDEX(adapter->NextEvent[RssId], EVENT_RING_SIZE);
Event = &EventRing->Ring[adapter->NextEvent[RssId]];
EventsProcessed++;
@@ -1253,9 +1368,11 @@ static u32 sxg_process_event_queue(struct adapter_t *adapter, u32 RssId)
WRITE_REG(adapter->UcodeRegs[RssId].EventRelease,
EVENT_RING_BATCH, FALSE);
EventsProcessed = 0;
- /* If we've processed our batch limit, break out of the */
- /* loop and return SXG_ISR_EVENT to arrange for us to */
- /* be called again */
+ /*
+ * If we've processed our batch limit, break out of the
+ * loop and return SXG_ISR_EVENT to arrange for us to
+ * be called again
+ */
if (Batches++ == EVENT_BATCH_LIMIT) {
SXG_TRACE(TRACE_SXG, SxgTraceBuffer,
TRACE_NOISY, "EvtLimit", Batches,
@@ -1266,14 +1383,10 @@ static u32 sxg_process_event_queue(struct adapter_t *adapter, u32 RssId)
}
}
#ifdef LINUX_HANDLES_RCV_INDICATION_LISTS
- /* */
/* Indicate any received dumb-nic frames */
- /* */
SXG_INDICATE_PACKETS(adapter, IndicationList, num_skbs);
#endif
- /* */
/* Release events back to the card. */
- /* */
if (EventsProcessed) {
WRITE_REG(adapter->UcodeRegs[RssId].EventRelease,
EventsProcessed, FALSE);
@@ -1295,21 +1408,25 @@ static u32 sxg_process_event_queue(struct adapter_t *adapter, u32 RssId)
*/
static void sxg_complete_slow_send(struct adapter_t *adapter)
{
- struct SXG_XMT_RING *XmtRing = &adapter->XmtRings[0];
- struct SXG_RING_INFO *XmtRingInfo = &adapter->XmtRingZeroInfo;
+ struct sxg_xmt_ring *XmtRing = &adapter->XmtRings[0];
+ struct sxg_ring_info *XmtRingInfo = &adapter->XmtRingZeroInfo;
u32 *ContextType;
- struct SXG_CMD *XmtCmd;
+ struct sxg_cmd *XmtCmd;
- /* NOTE - This lock is dropped and regrabbed in this loop. */
- /* This means two different processors can both be running */
- /* through this loop. Be *very* careful. */
+ /*
+ * NOTE - This lock is dropped and regrabbed in this loop.
+ * This means two different processors can both be running/
+ * through this loop. Be *very* careful.
+ */
spin_lock(&adapter->XmtZeroLock);
SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "CmpSnds",
adapter, XmtRingInfo->Head, XmtRingInfo->Tail, 0);
while (XmtRingInfo->Tail != *adapter->XmtRingZeroIndex) {
- /* Locate the current Cmd (ring descriptor entry), and */
- /* associated SGL, and advance the tail */
+ /*
+ * Locate the current Cmd (ring descriptor entry), and
+ * associated SGL, and advance the tail
+ */
SXG_RETURN_CMD(XmtRing, XmtRingInfo, XmtCmd, ContextType);
ASSERT(ContextType);
SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "CmpSnd",
@@ -1321,19 +1438,26 @@ static void sxg_complete_slow_send(struct adapter_t *adapter)
case SXG_SGL_DUMB:
{
struct sk_buff *skb;
+ struct sxg_scatter_gather *SxgSgl =
+ (struct sxg_scatter_gather *)ContextType;
+
/* Dumb-nic send. Command context is the dumb-nic SGL */
skb = (struct sk_buff *)ContextType;
+ skb = SxgSgl->DumbPacket;
/* Complete the send */
SXG_TRACE(TRACE_SXG, SxgTraceBuffer,
TRACE_IMPORTANT, "DmSndCmp", skb, 0,
0, 0);
ASSERT(adapter->Stats.XmtQLen);
- adapter->Stats.XmtQLen--; /* within XmtZeroLock */
+ adapter->Stats.XmtQLen--;/* within XmtZeroLock */
adapter->Stats.XmtOk++;
- /* Now drop the lock and complete the send back to */
- /* Microsoft. We need to drop the lock because */
- /* Microsoft can come back with a chimney send, which */
- /* results in a double trip in SxgTcpOuput */
+ /*
+ * Now drop the lock and complete the send
+ * back to Microsoft. We need to drop the lock
+ * because Microsoft can come back with a
+ * chimney send, which results in a double trip
+ * in SxgTcpOuput
+ */
spin_unlock(&adapter->XmtZeroLock);
SXG_COMPLETE_DUMB_SEND(adapter, skb);
/* and reacquire.. */
@@ -1356,22 +1480,21 @@ static void sxg_complete_slow_send(struct adapter_t *adapter)
* adapter - A pointer to our adapter structure
* Event - Receive event
*
- * Return
- * skb
+ * Return - skb
*/
-static struct sk_buff *sxg_slow_receive(struct adapter_t *adapter, struct SXG_EVENT *Event)
+static struct sk_buff *sxg_slow_receive(struct adapter_t *adapter,
+ struct sxg_event *Event)
{
- struct SXG_RCV_DATA_BUFFER_HDR *RcvDataBufferHdr;
+ u32 BufferSize = adapter->ReceiveBufferSize;
+ struct sxg_rcv_data_buffer_hdr *RcvDataBufferHdr;
struct sk_buff *Packet;
- RcvDataBufferHdr = (struct SXG_RCV_DATA_BUFFER_HDR*) Event->HostHandle;
+ RcvDataBufferHdr = (struct sxg_rcv_data_buffer_hdr *) Event->HostHandle;
ASSERT(RcvDataBufferHdr);
ASSERT(RcvDataBufferHdr->State == SXG_BUFFER_ONCARD);
- ASSERT(SXG_RECEIVE_DATA_LOCATION(RcvDataBufferHdr) ==
- RcvDataBufferHdr->VirtualAddress);
SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_IMPORTANT, "SlowRcv", Event,
RcvDataBufferHdr, RcvDataBufferHdr->State,
- RcvDataBufferHdr->VirtualAddress);
+ /*RcvDataBufferHdr->VirtualAddress*/ 0);
/* Drop rcv frames in non-running state */
switch (adapter->State) {
case SXG_STATE_RUNNING:
@@ -1385,6 +1508,11 @@ static struct sk_buff *sxg_slow_receive(struct adapter_t *adapter, struct SXG_EV
goto drop;
}
+ /*
+ * memcpy(SXG_RECEIVE_DATA_LOCATION(RcvDataBufferHdr),
+ * RcvDataBufferHdr->VirtualAddress, Event->Length);
+ */
+
/* Change buffer state to UPSTREAM */
RcvDataBufferHdr->State = SXG_BUFFER_UPSTREAM;
if (Event->Status & EVENT_STATUS_RCVERR) {
@@ -1400,8 +1528,9 @@ static struct sk_buff *sxg_slow_receive(struct adapter_t *adapter, struct SXG_EV
}
#if XXXTODO /* VLAN stuff */
/* If there's a VLAN tag, extract it and validate it */
- if (((struct ether_header*) (SXG_RECEIVE_DATA_LOCATION(RcvDataBufferHdr)))->
- EtherType == ETHERTYPE_VLAN) {
+ if (((struct ether_header *)
+ (SXG_RECEIVE_DATA_LOCATION(RcvDataBufferHdr)))->EtherType
+ == ETHERTYPE_VLAN) {
if (SxgExtractVlanHeader(adapter, RcvDataBufferHdr, Event) !=
STATUS_SUCCESS) {
SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY,
@@ -1412,27 +1541,35 @@ static struct sk_buff *sxg_slow_receive(struct adapter_t *adapter, struct SXG_EV
}
}
#endif
- /* */
/* Dumb-nic frame. See if it passes our mac filter and update stats */
- /* */
- if (!sxg_mac_filter(adapter, (struct ether_header*)
- SXG_RECEIVE_DATA_LOCATION(RcvDataBufferHdr),
- Event->Length)) {
- SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "RcvFiltr",
- Event, SXG_RECEIVE_DATA_LOCATION(RcvDataBufferHdr),
- Event->Length, 0);
- goto drop;
- }
+
+ /*
+ * ASK if (!sxg_mac_filter(adapter,
+ * SXG_RECEIVE_DATA_LOCATION(RcvDataBufferHdr),
+ * Event->Length)) {
+ * SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "RcvFiltr",
+ * Event, SXG_RECEIVE_DATA_LOCATION(RcvDataBufferHdr),
+ * Event->Length, 0);
+ * goto drop;
+ * }
+ */
Packet = RcvDataBufferHdr->SxgDumbRcvPacket;
+ SXG_ADJUST_RCV_PACKET(Packet, RcvDataBufferHdr, Event);
+ Packet->protocol = eth_type_trans(Packet, adapter->netdev);
SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_IMPORTANT, "DumbRcv",
RcvDataBufferHdr, Packet, Event->Length, 0);
- /* */
/* Lastly adjust the receive packet length. */
- /* */
- SXG_ADJUST_RCV_PACKET(Packet, RcvDataBufferHdr, Event);
-
+ RcvDataBufferHdr->SxgDumbRcvPacket = NULL;
+ SXG_ALLOCATE_RCV_PACKET(adapter, RcvDataBufferHdr, BufferSize);
+ if (RcvDataBufferHdr->skb)
+ {
+ spin_lock(&adapter->RcvQLock);
+ SXG_FREE_RCV_DATA_BUFFER(adapter, RcvDataBufferHdr);
+ adapter->RcvBuffersOnCard ++;
+ spin_unlock(&adapter->RcvQLock);
+ }
return (Packet);
drop:
@@ -1453,8 +1590,7 @@ static struct sk_buff *sxg_slow_receive(struct adapter_t *adapter, struct SXG_EV
* adapter - Adapter structure
* ErrorStatus - 4-byte receive error status
*
- * Return Value:
- * None
+ * Return Value : None
*/
static void sxg_process_rcv_error(struct adapter_t *adapter, u32 ErrorStatus)
{
@@ -1532,11 +1668,10 @@ static void sxg_process_rcv_error(struct adapter_t *adapter, u32 ErrorStatus)
* pether - Ethernet header
* length - Frame length
*
- * Return Value:
- * TRUE if the frame is to be allowed
+ * Return Value : TRUE if the frame is to be allowed
*/
-static bool sxg_mac_filter(struct adapter_t *adapter, struct ether_header *EtherHdr,
- ushort length)
+static bool sxg_mac_filter(struct adapter_t *adapter,
+ struct ether_header *EtherHdr, ushort length)
{
bool EqualAddr;
@@ -1560,7 +1695,7 @@ static bool sxg_mac_filter(struct adapter_t *adapter, struct ether_header *Ether
return (TRUE);
}
if (adapter->MacFilter & MAC_MCAST) {
- struct SXG_MULTICAST_ADDRESS *MulticastAddrs =
+ struct sxg_multicast_address *MulticastAddrs =
adapter->MulticastAddrs;
while (MulticastAddrs) {
ETHER_EQ_ADDR(MulticastAddrs->Address,
@@ -1581,9 +1716,11 @@ static bool sxg_mac_filter(struct adapter_t *adapter, struct ether_header *Ether
}
}
} else if (adapter->MacFilter & MAC_DIRECTED) {
- /* Not broadcast or multicast. Must be directed at us or */
- /* the card is in promiscuous mode. Either way, consider it */
- /* ours if MAC_DIRECTED is set */
+ /*
+ * Not broadcast or multicast. Must be directed at us or
+ * the card is in promiscuous mode. Either way, consider it
+ * ours if MAC_DIRECTED is set
+ */
adapter->Stats.DumbRcvUcastPkts++;
adapter->Stats.DumbRcvUcastBytes += length;
adapter->Stats.DumbRcvPkts++;
@@ -1663,12 +1800,12 @@ static void sxg_deregister_interrupt(struct adapter_t *adapter)
*/
static int sxg_if_init(struct adapter_t *adapter)
{
- p_net_device dev = adapter->netdev;
+ struct net_device *dev = adapter->netdev;
int status = 0;
- DBG_ERROR("sxg: %s (%s) ENTER states[%d:%d:%d] flags[%x]\n",
+ DBG_ERROR("sxg: %s (%s) ENTER states[%d:%d] flags[%x]\n",
__func__, adapter->netdev->name,
- adapter->queues_initialized, adapter->state,
+ adapter->state,
adapter->linkstate, dev->flags);
/* adapter should be down at this point */
@@ -1711,15 +1848,13 @@ static int sxg_if_init(struct adapter_t *adapter)
adapter->state = ADAPT_UP;
- /*
- * clear any pending events, then enable interrupts
- */
+ /* clear any pending events, then enable interrupts */
DBG_ERROR("sxg: %s ENABLE interrupts(slic)\n", __func__);
return (STATUS_SUCCESS);
}
-static int sxg_entry_open(p_net_device dev)
+static int sxg_entry_open(struct net_device *dev)
{
struct adapter_t *adapter = (struct adapter_t *) netdev_priv(dev);
int status;
@@ -1774,18 +1909,24 @@ static int sxg_entry_open(p_net_device dev)
static void __devexit sxg_entry_remove(struct pci_dev *pcidev)
{
- p_net_device dev = pci_get_drvdata(pcidev);
+ struct net_device *dev = pci_get_drvdata(pcidev);
u32 mmio_start = 0;
unsigned int mmio_len = 0;
struct adapter_t *adapter = (struct adapter_t *) netdev_priv(dev);
+ set_bit(ADAPT_DOWN, &adapter->state);
+ flush_scheduled_work();
+
+ /* Deallocate Resources */
+
+ SxgFreeResources(adapter);
+
ASSERT(adapter);
DBG_ERROR("sxg: %s ENTER dev[%p] adapter[%p]\n", __func__, dev,
adapter);
sxg_deregister_interrupt(adapter);
sxg_unmap_mmio_space(adapter);
DBG_ERROR("sxg: %s unregister_netdev\n", __func__);
- unregister_netdev(dev);
mmio_start = pci_resource_start(pcidev, 0);
mmio_len = pci_resource_len(pcidev, 0);
@@ -1794,16 +1935,30 @@ static void __devexit sxg_entry_remove(struct pci_dev *pcidev)
mmio_start, mmio_len);
release_mem_region(mmio_start, mmio_len);
+/*
DBG_ERROR("sxg: %s iounmap dev->base_addr[%x]\n", __func__,
(unsigned int)dev->base_addr);
iounmap((char *)dev->base_addr);
+*/
+ mmio_start = pci_resource_start(pcidev, 2);
+ mmio_len = pci_resource_len(pcidev, 2);
+
+ DBG_ERROR("sxg: %s rel_region(2) start[%x] len[%x]\n", __FUNCTION__,
+ mmio_start, mmio_len);
+ release_mem_region(mmio_start, mmio_len);
+
+ iounmap((char *)dev->base_addr);
+ unregister_netdev(dev);
+ //pci_release_regions(pcidev);
+ //free_netdev(dev);
+ pci_disable_device(pcidev);
DBG_ERROR("sxg: %s deallocate device\n", __func__);
kfree(dev);
DBG_ERROR("sxg: %s EXIT\n", __func__);
}
-static int sxg_entry_halt(p_net_device dev)
+static int sxg_entry_halt(struct net_device *dev)
{
struct adapter_t *adapter = (struct adapter_t *) netdev_priv(dev);
@@ -1819,24 +1974,31 @@ static int sxg_entry_halt(p_net_device dev)
DBG_ERROR("sxg: %s (%s) EXIT\n", __func__, dev->name);
DBG_ERROR("sxg: %s EXIT\n", __func__);
+
+ /* Disable interrupts */
+ SXG_DISABLE_ALL_INTERRUPTS(adapter);
+
spin_unlock_irqrestore(&sxg_global.driver_lock, sxg_global.flags);
+
return (STATUS_SUCCESS);
}
-static int sxg_ioctl(p_net_device dev, struct ifreq *rq, int cmd)
+static int sxg_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{
ASSERT(rq);
-/* DBG_ERROR("sxg: %s cmd[%x] rq[%p] dev[%p]\n", __func__, cmd, rq, dev); */
+/* DBG_ERROR("sxg: %s cmd[%x] rq[%p] dev[%p]\n", __func__, cmd, rq, dev);*/
switch (cmd) {
case SIOCSLICSETINTAGG:
{
-/* struct adapter_t *adapter = (struct adapter_t *) netdev_priv(dev); */
+ /* struct adapter_t *adapter = (struct adapter_t *)
+ * netdev_priv(dev);
+ */
u32 data[7];
u32 intagg;
if (copy_from_user(data, rq->ifr_data, 28)) {
- DBG_ERROR
- ("copy_from_user FAILED getting initial params\n");
+ DBG_ERROR("copy_from_user FAILED getting \
+ initial params\n");
return -EFAULT;
}
intagg = data[0];
@@ -1847,7 +2009,7 @@ static int sxg_ioctl(p_net_device dev, struct ifreq *rq, int cmd)
}
default:
-/* DBG_ERROR("sxg: %s UNSUPPORTED[%x]\n", __func__, cmd); */
+ /* DBG_ERROR("sxg: %s UNSUPPORTED[%x]\n", __func__, cmd); */
return -EOPNOTSUPP;
}
return 0;
@@ -1856,23 +2018,26 @@ static int sxg_ioctl(p_net_device dev, struct ifreq *rq, int cmd)
#define NORMAL_ETHFRAME 0
/*
- *
* sxg_send_packets - Send a skb packet
*
* Arguments:
- * skb - The packet to send
- * dev - Our linux net device that refs our adapter
+ * skb - The packet to send
+ * dev - Our linux net device that refs our adapter
*
* Return:
* 0 regardless of outcome XXXTODO refer to e1000 driver
*/
-static int sxg_send_packets(struct sk_buff *skb, p_net_device dev)
+static int sxg_send_packets(struct sk_buff *skb, struct net_device *dev)
{
struct adapter_t *adapter = (struct adapter_t *) netdev_priv(dev);
u32 status = STATUS_SUCCESS;
- DBG_ERROR("sxg: %s ENTER sxg_send_packets skb[%p]\n", __func__,
- skb);
+ /*
+ * DBG_ERROR("sxg: %s ENTER sxg_send_packets skb[%p]\n", __FUNCTION__,
+ * skb);
+ */
+ printk("ASK:sxg_send_packets: skb[%p]\n", skb);
+
/* Check the adapter state */
switch (adapter->State) {
case SXG_STATE_INITIALIZING:
@@ -1909,7 +2074,7 @@ static int sxg_send_packets(struct sk_buff *skb, p_net_device dev)
/* reject & complete all the packets if they cant be sent */
if (status != STATUS_SUCCESS) {
#if XXXTODO
-/* sxg_send_packets_fail(adapter, skb, status); */
+ /* sxg_send_packets_fail(adapter, skb, status); */
#else
SXG_DROP_DUMB_SEND(adapter, skb);
adapter->stats.tx_dropped++;
@@ -1931,18 +2096,19 @@ static int sxg_send_packets(struct sk_buff *skb, p_net_device dev)
* adapter - Pointer to our adapter structure
* skb - The packet to be sent
*
- * Return -
- * STATUS of send
+ * Return - STATUS of send
*/
static int sxg_transmit_packet(struct adapter_t *adapter, struct sk_buff *skb)
{
- struct SCATTER_GATHER_LIST *pSgl;
- struct SXG_SCATTER_GATHER *SxgSgl;
- void *SglBuffer;
- u32 SglBufferLength;
+ struct sxg_x64_sgl *pSgl;
+ struct sxg_scatter_gather *SxgSgl;
+ /* void *SglBuffer; */
+ /* u32 SglBufferLength; */
- /* The vast majority of work is done in the shared */
- /* sxg_dumb_sgl routine. */
+ /*
+ * The vast majority of work is done in the shared
+ * sxg_dumb_sgl routine.
+ */
SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "DumbSend",
adapter, skb, 0, 0);
@@ -1956,8 +2122,8 @@ static int sxg_transmit_packet(struct adapter_t *adapter, struct sk_buff *skb)
return (STATUS_RESOURCES);
}
ASSERT(SxgSgl->adapter == adapter);
- SglBuffer = SXG_SGL_BUFFER(SxgSgl);
- SglBufferLength = SXG_SGL_BUF_SIZE;
+ /*SglBuffer = SXG_SGL_BUFFER(SxgSgl);
+ SglBufferLength = SXG_SGL_BUF_SIZE; */
SxgSgl->VlanTag.VlanTci = 0;
SxgSgl->VlanTag.VlanTpid = 0;
SxgSgl->Type = SXG_SGL_DUMB;
@@ -1966,7 +2132,7 @@ static int sxg_transmit_packet(struct adapter_t *adapter, struct sk_buff *skb)
/* Call the common sxg_dumb_sgl routine to complete the send. */
sxg_dumb_sgl(pSgl, SxgSgl);
- /* Return success sxg_dumb_sgl (or something later) will complete it. */
+ /* Return success sxg_dumb_sgl (or something later) will complete it.*/
return (STATUS_SUCCESS);
}
@@ -1975,23 +2141,24 @@ static int sxg_transmit_packet(struct adapter_t *adapter, struct sk_buff *skb)
*
* Arguments:
* pSgl -
- * SxgSgl - SXG_SCATTER_GATHER
+ * SxgSgl - struct sxg_scatter_gather
*
* Return Value:
* None.
*/
-static void sxg_dumb_sgl(struct SCATTER_GATHER_LIST *pSgl, struct SXG_SCATTER_GATHER *SxgSgl)
+static void sxg_dumb_sgl(struct sxg_x64_sgl *pSgl,
+ struct sxg_scatter_gather *SxgSgl)
{
struct adapter_t *adapter = SxgSgl->adapter;
struct sk_buff *skb = SxgSgl->DumbPacket;
/* For now, all dumb-nic sends go on RSS queue zero */
- struct SXG_XMT_RING *XmtRing = &adapter->XmtRings[0];
- struct SXG_RING_INFO *XmtRingInfo = &adapter->XmtRingZeroInfo;
- struct SXG_CMD *XmtCmd = NULL;
-/* u32 Index = 0; */
+ struct sxg_xmt_ring *XmtRing = &adapter->XmtRings[0];
+ struct sxg_ring_info *XmtRingInfo = &adapter->XmtRingZeroInfo;
+ struct sxg_cmd *XmtCmd = NULL;
+ /* u32 Index = 0; */
u32 DataLength = skb->len;
-/* unsigned int BufLen; */
-/* u32 SglOffset; */
+ /* unsigned int BufLen; */
+ /* u32 SglOffset; */
u64 phys_addr;
SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "DumbSgl",
@@ -2001,13 +2168,15 @@ static void sxg_dumb_sgl(struct SCATTER_GATHER_LIST *pSgl, struct SXG_SCATTER_GA
SxgSgl->pSgl = pSgl;
/* Sanity check that our SGL format is as we expect. */
- ASSERT(sizeof(SXG_X64_SGE) == sizeof(SCATTER_GATHER_ELEMENT));
+ ASSERT(sizeof(struct sxg_x64_sge) == sizeof(struct sxg_x64_sge));
/* Shouldn't be a vlan tag on this frame */
ASSERT(SxgSgl->VlanTag.VlanTci == 0);
ASSERT(SxgSgl->VlanTag.VlanTpid == 0);
- /* From here below we work with the SGL placed in our */
- /* buffer. */
+ /*
+ * From here below we work with the SGL placed in our
+ * buffer.
+ */
SxgSgl->Sgl.NumberOfElements = 1;
@@ -2015,8 +2184,10 @@ static void sxg_dumb_sgl(struct SCATTER_GATHER_LIST *pSgl, struct SXG_SCATTER_GA
spin_lock(&adapter->XmtZeroLock);
SXG_GET_CMD(XmtRing, XmtRingInfo, XmtCmd, SxgSgl);
if (XmtCmd == NULL) {
- /* Call sxg_complete_slow_send to see if we can */
- /* free up any XmtRingZero entries and then try again */
+ /*
+ * Call sxg_complete_slow_send to see if we can
+ * free up any XmtRingZero entries and then try again
+ */
spin_unlock(&adapter->XmtZeroLock);
sxg_complete_slow_send(adapter);
spin_lock(&adapter->XmtZeroLock);
@@ -2045,40 +2216,26 @@ static void sxg_dumb_sgl(struct SCATTER_GATHER_LIST *pSgl, struct SXG_SCATTER_GA
adapter->Stats.DumbXmtUcastBytes += DataLength;
}
#endif
- /* Fill in the command */
- /* Copy out the first SGE to the command and adjust for offset */
- phys_addr =
- pci_map_single(adapter->pcidev, skb->data, skb->len,
+ /*
+ * Fill in the command
+ * Copy out the first SGE to the command and adjust for offset
+ */
+ phys_addr = pci_map_single(adapter->pcidev, skb->data, skb->len,
PCI_DMA_TODEVICE);
- XmtCmd->Buffer.FirstSgeAddress = SXG_GET_ADDR_HIGH(phys_addr);
- XmtCmd->Buffer.FirstSgeAddress = XmtCmd->Buffer.FirstSgeAddress << 32;
- XmtCmd->Buffer.FirstSgeAddress =
- XmtCmd->Buffer.FirstSgeAddress | SXG_GET_ADDR_LOW(phys_addr);
-/* XmtCmd->Buffer.FirstSgeAddress = SxgSgl->Sgl.Elements[Index].Address; */
-/* XmtCmd->Buffer.FirstSgeAddress.LowPart += MdlOffset; */
+ memset(XmtCmd, '\0', sizeof(*XmtCmd));
+ XmtCmd->Buffer.FirstSgeAddress = phys_addr;
XmtCmd->Buffer.FirstSgeLength = DataLength;
- /* Set a pointer to the remaining SGL entries */
-/* XmtCmd->Sgl = SxgSgl->PhysicalAddress; */
- /* Advance the physical address of the SxgSgl structure to */
- /* the second SGE */
-/* SglOffset = (u32)((u32 *)(&SxgSgl->Sgl.Elements[Index+1]) - */
-/* (u32 *)SxgSgl); */
-/* XmtCmd->Sgl.LowPart += SglOffset; */
XmtCmd->Buffer.SgeOffset = 0;
- /* Note - TotalLength might be overwritten with MSS below.. */
XmtCmd->Buffer.TotalLength = DataLength;
- XmtCmd->SgEntries = 1; /*(ushort)(SxgSgl->Sgl.NumberOfElements - Index); */
+ XmtCmd->SgEntries = 1;
XmtCmd->Flags = 0;
- /* */
- /* Advance transmit cmd descripter by 1. */
- /* NOTE - See comments in SxgTcpOutput where we write */
- /* to the XmtCmd register regarding CPU ID values and/or */
- /* multiple commands. */
- /* */
- /* */
+ /*
+ * Advance transmit cmd descripter by 1.
+ * NOTE - See comments in SxgTcpOutput where we write
+ * to the XmtCmd register regarding CPU ID values and/or
+ * multiple commands.
+ */
WRITE_REG(adapter->UcodeRegs[0].XmtCmd, 1, TRUE);
- /* */
- /* */
adapter->Stats.XmtQLen++; /* Stats within lock */
spin_unlock(&adapter->XmtZeroLock);
SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "XDumSgl2",
@@ -2086,29 +2243,31 @@ static void sxg_dumb_sgl(struct SCATTER_GATHER_LIST *pSgl, struct SXG_SCATTER_GA
return;
abortcmd:
- /* NOTE - Only jump to this label AFTER grabbing the */
- /* XmtZeroLock, and DO NOT DROP IT between the */
- /* command allocation and the following abort. */
+ /*
+ * NOTE - Only jump to this label AFTER grabbing the
+ * XmtZeroLock, and DO NOT DROP IT between the
+ * command allocation and the following abort.
+ */
if (XmtCmd) {
SXG_ABORT_CMD(XmtRingInfo);
}
spin_unlock(&adapter->XmtZeroLock);
-/* failsgl: */
- /* Jump to this label if failure occurs before the */
- /* XmtZeroLock is grabbed */
+/*
+ * failsgl:
+ * Jump to this label if failure occurs before the
+ * XmtZeroLock is grabbed
+ */
adapter->Stats.XmtErrors++;
SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_IMPORTANT, "DumSGFal",
pSgl, SxgSgl, XmtRingInfo->Head, XmtRingInfo->Tail);
-
- SXG_COMPLETE_DUMB_SEND(adapter, SxgSgl->DumbPacket); /* SxgSgl->DumbPacket is the skb */
+ /* SxgSgl->DumbPacket is the skb */
+ SXG_COMPLETE_DUMB_SEND(adapter, SxgSgl->DumbPacket);
}
-/***************************************************************
- * Link management functions
- ***************************************************************/
-
/*
+ * Link management functions
+ *
* sxg_initialize_link - Initialize the link stuff
*
* Arguments -
@@ -2119,7 +2278,7 @@ static void sxg_dumb_sgl(struct SCATTER_GATHER_LIST *pSgl, struct SXG_SCATTER_GA
*/
static int sxg_initialize_link(struct adapter_t *adapter)
{
- struct SXG_HW_REGS *HwRegs = adapter->HwRegs;
+ struct sxg_hw_regs *HwRegs = adapter->HwRegs;
u32 Value;
u32 ConfigData;
u32 MaxFrame;
@@ -2140,15 +2299,17 @@ static int sxg_initialize_link(struct adapter_t *adapter)
/* Reset all MAC modules */
WRITE_REG(HwRegs->MacConfig0, AXGMAC_CFG0_SUB_RESET, TRUE);
- /* Link address 0 */
- /* XXXTODO - This assumes the MAC address (0a:0b:0c:0d:0e:0f) */
- /* is stored with the first nibble (0a) in the byte 0 */
- /* of the Mac address. Possibly reverse? */
- Value = *(u32 *) adapter->MacAddr;
+ /*
+ * Link address 0
+ * XXXTODO - This assumes the MAC address (0a:0b:0c:0d:0e:0f)
+ * is stored with the first nibble (0a) in the byte 0
+ * of the Mac address. Possibly reverse?
+ */
+ Value = *(u32 *) adapter->macaddr;
WRITE_REG(HwRegs->LinkAddress0Low, Value, TRUE);
/* also write the MAC address to the MAC. Endian is reversed. */
WRITE_REG(HwRegs->MacAddressLow, ntohl(Value), TRUE);
- Value = (*(u16 *) & adapter->MacAddr[4] & 0x0000FFFF);
+ Value = (*(u16 *) & adapter->macaddr[4] & 0x0000FFFF);
WRITE_REG(HwRegs->LinkAddress0High, Value | LINK_ADDRESS_ENABLE, TRUE);
/* endian swap for the MAC (put high bytes in bits [31:16], swapped) */
Value = ntohl(Value);
@@ -2167,30 +2328,41 @@ static int sxg_initialize_link(struct adapter_t *adapter)
WRITE_REG(HwRegs->MacConfig0, 0, TRUE);
/* Configure MAC */
- WRITE_REG(HwRegs->MacConfig1, (AXGMAC_CFG1_XMT_PAUSE | /* Allow sending of pause */
- AXGMAC_CFG1_XMT_EN | /* Enable XMT */
- AXGMAC_CFG1_RCV_PAUSE | /* Enable detection of pause */
- AXGMAC_CFG1_RCV_EN | /* Enable receive */
- AXGMAC_CFG1_SHORT_ASSERT | /* short frame detection */
- AXGMAC_CFG1_CHECK_LEN | /* Verify frame length */
- AXGMAC_CFG1_GEN_FCS | /* Generate FCS */
- AXGMAC_CFG1_PAD_64), /* Pad frames to 64 bytes */
- TRUE);
+ WRITE_REG(HwRegs->MacConfig1, (
+ /* Allow sending of pause */
+ AXGMAC_CFG1_XMT_PAUSE |
+ /* Enable XMT */
+ AXGMAC_CFG1_XMT_EN |
+ /* Enable detection of pause */
+ AXGMAC_CFG1_RCV_PAUSE |
+ /* Enable receive */
+ AXGMAC_CFG1_RCV_EN |
+ /* short frame detection */
+ AXGMAC_CFG1_SHORT_ASSERT |
+ /* Verify frame length */
+ AXGMAC_CFG1_CHECK_LEN |
+ /* Generate FCS */
+ AXGMAC_CFG1_GEN_FCS |
+ /* Pad frames to 64 bytes */
+ AXGMAC_CFG1_PAD_64),
+ TRUE);
/* Set AXGMAC max frame length if jumbo. Not needed for standard MTU */
if (adapter->JumboEnabled) {
WRITE_REG(HwRegs->MacMaxFrameLen, AXGMAC_MAXFRAME_JUMBO, TRUE);
}
- /* AMIIM Configuration Register - */
- /* The value placed in the AXGMAC_AMIIM_CFG_HALF_CLOCK portion */
- /* (bottom bits) of this register is used to determine the */
- /* MDC frequency as specified in the A-XGMAC Design Document. */
- /* This value must not be zero. The following value (62 or 0x3E) */
- /* is based on our MAC transmit clock frequency (MTCLK) of 312.5 MHz. */
- /* Given a maximum MDIO clock frequency of 2.5 MHz (see the PHY spec), */
- /* we get: 312.5/(2*(X+1)) < 2.5 ==> X = 62. */
- /* This value happens to be the default value for this register, */
- /* so we really don't have to do this. */
+ /*
+ * AMIIM Configuration Register -
+ * The value placed in the AXGMAC_AMIIM_CFG_HALF_CLOCK portion
+ * (bottom bits) of this register is used to determine the MDC frequency
+ * as specified in the A-XGMAC Design Document. This value must not be
+ * zero. The following value (62 or 0x3E) is based on our MAC transmit
+ * clock frequency (MTCLK) of 312.5 MHz. Given a maximum MDIO clock
+ * frequency of 2.5 MHz (see the PHY spec), we get:
+ * 312.5/(2*(X+1)) < 2.5 ==> X = 62.
+ * This value happens to be the default value for this register, so we
+ * really don't have to do this.
+ */
WRITE_REG(HwRegs->MacAmiimConfig, 0x0000003E, TRUE);
/* Power up and enable PHY and XAUI/XGXS/Serdes logic */
@@ -2200,14 +2372,22 @@ static int sxg_initialize_link(struct adapter_t *adapter)
LS_XGXS_CTL | LS_PHY_CLK_EN | LS_ATTN_ALARM), TRUE);
DBG_ERROR("After Power Up and enable PHY in sxg_initialize_link\n");
- /* Per information given by Aeluros, wait 100 ms after removing reset. */
- /* It's not enough to wait for the self-clearing reset bit in reg 0 to clear. */
+ /*
+ * Per information given by Aeluros, wait 100 ms after removing reset.
+ * It's not enough to wait for the self-clearing reset bit in reg 0 to
+ * clear.
+ */
mdelay(100);
- /* Verify the PHY has come up by checking that the Reset bit has cleared. */
- status = sxg_read_mdio_reg(adapter, MIIM_DEV_PHY_PMA, /* PHY PMA/PMD module */
- PHY_PMA_CONTROL1, /* PMA/PMD control register */
- &Value);
+ /* Verify the PHY has come up by checking that the Reset bit has
+ * cleared.
+ */
+ status = sxg_read_mdio_reg(adapter,
+ MIIM_DEV_PHY_PMA, /* PHY PMA/PMD module */
+ PHY_PMA_CONTROL1, /* PMA/PMD control register */
+ &Value);
+ DBG_ERROR("After sxg_read_mdio_reg Value[%x] fail=%x\n", Value,
+ (Value & PMA_CONTROL1_RESET));
if (status != STATUS_SUCCESS)
return (STATUS_FAILURE);
if (Value & PMA_CONTROL1_RESET) /* reset complete if bit is 0 */
@@ -2228,16 +2408,26 @@ static int sxg_initialize_link(struct adapter_t *adapter)
return (STATUS_FAILURE);
/* Enable the Link Alarm */
- status = sxg_write_mdio_reg(adapter, MIIM_DEV_PHY_PMA, /* PHY PMA/PMD module */
- LASI_CONTROL, /* LASI control register */
- LASI_CTL_LS_ALARM_ENABLE); /* enable link alarm bit */
+
+ /* MIIM_DEV_PHY_PMA - PHY PMA/PMD module
+ * LASI_CONTROL - LASI control register
+ * LASI_CTL_LS_ALARM_ENABLE - enable link alarm bit
+ */
+ status = sxg_write_mdio_reg(adapter, MIIM_DEV_PHY_PMA,
+ LASI_CONTROL,
+ LASI_CTL_LS_ALARM_ENABLE);
if (status != STATUS_SUCCESS)
return (STATUS_FAILURE);
/* XXXTODO - temporary - verify bit is set */
- status = sxg_read_mdio_reg(adapter, MIIM_DEV_PHY_PMA, /* PHY PMA/PMD module */
- LASI_CONTROL, /* LASI control register */
+
+ /* MIIM_DEV_PHY_PMA - PHY PMA/PMD module
+ * LASI_CONTROL - LASI control register
+ */
+ status = sxg_read_mdio_reg(adapter, MIIM_DEV_PHY_PMA,
+ LASI_CONTROL,
&Value);
+
if (status != STATUS_SUCCESS)
return (STATUS_FAILURE);
if (!(Value & LASI_CTL_LS_ALARM_ENABLE)) {
@@ -2277,21 +2467,25 @@ static int sxg_initialize_link(struct adapter_t *adapter)
static int sxg_phy_init(struct adapter_t *adapter)
{
u32 Value;
- struct PHY_UCODE *p;
+ struct phy_ucode *p;
int status;
DBG_ERROR("ENTER %s\n", __func__);
- /* Read a register to identify the PHY type */
- status = sxg_read_mdio_reg(adapter, MIIM_DEV_PHY_PMA, /* PHY PMA/PMD module */
- 0xC205, /* PHY ID register (?) */
- &Value); /* XXXTODO - add def */
+ /* MIIM_DEV_PHY_PMA - PHY PMA/PMD module
+ * 0xC205 - PHY ID register (?)
+ * &Value - XXXTODO - add def
+ */
+ status = sxg_read_mdio_reg(adapter, MIIM_DEV_PHY_PMA,
+ 0xC205,
+ &Value);
if (status != STATUS_SUCCESS)
return (STATUS_FAILURE);
- if (Value == 0x0012) { /* 0x0012 == AEL2005C PHY(?) - XXXTODO - add def */
- DBG_ERROR
- ("AEL2005C PHY detected. Downloading PHY microcode.\n");
+ if (Value == 0x0012) {
+ /* 0x0012 == AEL2005C PHY(?) - XXXTODO - add def */
+ DBG_ERROR("AEL2005C PHY detected. Downloading PHY \
+ microcode.\n");
/* Initialize AEL2005C PHY and download PHY microcode */
for (p = PhyUcode; p->Addr != 0xFFFF; p++) {
@@ -2299,10 +2493,13 @@ static int sxg_phy_init(struct adapter_t *adapter)
/* if address == 0, data == sleep time in ms */
mdelay(p->Data);
} else {
- /* write the given data to the specified address */
- status = sxg_write_mdio_reg(adapter, MIIM_DEV_PHY_PMA, /* PHY PMA/PMD module */
- p->Addr, /* PHY address */
- p->Data); /* PHY data */
+ /* write the given data to the specified address */
+ status = sxg_write_mdio_reg(adapter,
+ MIIM_DEV_PHY_PMA,
+ /* PHY address */
+ p->Addr,
+ /* PHY data */
+ p->Data);
if (status != STATUS_SUCCESS)
return (STATUS_FAILURE);
}
@@ -2324,7 +2521,7 @@ static int sxg_phy_init(struct adapter_t *adapter)
*/
static void sxg_link_event(struct adapter_t *adapter)
{
- struct SXG_HW_REGS *HwRegs = adapter->HwRegs;
+ struct sxg_hw_regs *HwRegs = adapter->HwRegs;
enum SXG_LINK_STATE LinkState;
int status;
u32 Value;
@@ -2336,18 +2533,22 @@ static void sxg_link_event(struct adapter_t *adapter)
/* Check the Link Status register. We should have a Link Alarm. */
READ_REG(HwRegs->LinkStatus, Value);
if (Value & LS_LINK_ALARM) {
- /* We got a Link Status alarm. First, pause to let the */
- /* link state settle (it can bounce a number of times) */
+ /*
+ * We got a Link Status alarm. First, pause to let the
+ * link state settle (it can bounce a number of times)
+ */
mdelay(10);
/* Now clear the alarm by reading the LASI status register. */
- status = sxg_read_mdio_reg(adapter, MIIM_DEV_PHY_PMA, /* PHY PMA/PMD module */
- LASI_STATUS, /* LASI status register */
+ /* MIIM_DEV_PHY_PMA - PHY PMA/PMD module */
+ status = sxg_read_mdio_reg(adapter, MIIM_DEV_PHY_PMA,
+ /* LASI status register */
+ LASI_STATUS,
&Value);
if (status != STATUS_SUCCESS) {
DBG_ERROR("Error reading LASI Status MDIO register!\n");
sxg_link_state(adapter, SXG_LINK_DOWN);
-/* ASSERT(0); */
+ /* ASSERT(0); */
}
ASSERT(Value & LASI_STATUS_LS_ALARM);
@@ -2357,14 +2558,16 @@ static void sxg_link_event(struct adapter_t *adapter)
DBG_ERROR("SXG: Link Alarm occurred. Link is %s\n",
((LinkState == SXG_LINK_UP) ? "UP" : "DOWN"));
} else {
- /* XXXTODO - Assuming Link Attention is only being generated for the */
- /* Link Alarm pin (and not for a XAUI Link Status change), then it's */
- /* impossible to get here. Yet we've gotten here twice (under extreme */
- /* conditions - bouncing the link up and down many times a second). */
- /* Needs further investigation. */
+ /*
+ * XXXTODO - Assuming Link Attention is only being generated
+ * for the Link Alarm pin (and not for a XAUI Link Status change)
+ * , then it's impossible to get here. Yet we've gotten here
+ * twice (under extreme conditions - bouncing the link up and
+ * down many times a second). Needs further investigation.
+ */
DBG_ERROR("SXG: sxg_link_event: Can't get here!\n");
DBG_ERROR("SXG: Link Status == 0x%08X.\n", Value);
-/* ASSERT(0); */
+ /* ASSERT(0); */
}
DBG_ERROR("EXIT %s\n", __func__);
@@ -2389,10 +2592,15 @@ static enum SXG_LINK_STATE sxg_get_link_state(struct adapter_t *adapter)
SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "GetLink",
adapter, 0, 0, 0);
- /* Per the Xenpak spec (and the IEEE 10Gb spec?), the link is up if */
- /* the following 3 bits (from 3 different MDIO registers) are all true. */
- status = sxg_read_mdio_reg(adapter, MIIM_DEV_PHY_PMA, /* PHY PMA/PMD module */
- PHY_PMA_RCV_DET, /* PMA/PMD Receive Signal Detect register */
+ /*
+ * Per the Xenpak spec (and the IEEE 10Gb spec?), the link is up if
+ * the following 3 bits (from 3 different MDIO registers) are all true.
+ */
+
+ /* MIIM_DEV_PHY_PMA - PHY PMA/PMD module */
+ status = sxg_read_mdio_reg(adapter, MIIM_DEV_PHY_PMA,
+ /* PMA/PMD Receive Signal Detect register */
+ PHY_PMA_RCV_DET,
&Value);
if (status != STATUS_SUCCESS)
goto bad;
@@ -2401,8 +2609,10 @@ static enum SXG_LINK_STATE sxg_get_link_state(struct adapter_t *adapter)
if (!(Value & PMA_RCV_DETECT))
return (SXG_LINK_DOWN);
- status = sxg_read_mdio_reg(adapter, MIIM_DEV_PHY_PCS, /* PHY PCS module */
- PHY_PCS_10G_STATUS1, /* PCS 10GBASE-R Status 1 register */
+ /* MIIM_DEV_PHY_PCS - PHY PCS module */
+ status = sxg_read_mdio_reg(adapter, MIIM_DEV_PHY_PCS,
+ /* PCS 10GBASE-R Status 1 register */
+ PHY_PCS_10G_STATUS1,
&Value);
if (status != STATUS_SUCCESS)
goto bad;
@@ -2411,8 +2621,9 @@ static enum SXG_LINK_STATE sxg_get_link_state(struct adapter_t *adapter)
if (!(Value & PCS_10B_BLOCK_LOCK))
return (SXG_LINK_DOWN);
- status = sxg_read_mdio_reg(adapter, MIIM_DEV_PHY_XS, /* PHY XS module */
- PHY_XS_LANE_STATUS, /* XS Lane Status register */
+ status = sxg_read_mdio_reg(adapter, MIIM_DEV_PHY_XS,/* PHY XS module */
+ /* XS Lane Status register */
+ PHY_XS_LANE_STATUS,
&Value);
if (status != STATUS_SUCCESS)
goto bad;
@@ -2427,7 +2638,7 @@ static enum SXG_LINK_STATE sxg_get_link_state(struct adapter_t *adapter)
return (SXG_LINK_UP);
bad:
- /* An error occurred reading an MDIO register. This shouldn't happen. */
+ /* An error occurred reading an MDIO register. This shouldn't happen. */
DBG_ERROR("Error reading an MDIO register!\n");
ASSERT(0);
return (SXG_LINK_DOWN);
@@ -2460,20 +2671,24 @@ static void sxg_indicate_link_state(struct adapter_t *adapter,
* Return
* None
*/
-static void sxg_link_state(struct adapter_t *adapter, enum SXG_LINK_STATE LinkState)
+static void sxg_link_state(struct adapter_t *adapter,
+ enum SXG_LINK_STATE LinkState)
{
SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_IMPORTANT, "LnkINDCT",
adapter, LinkState, adapter->LinkState, adapter->State);
DBG_ERROR("ENTER %s\n", __func__);
- /* Hold the adapter lock during this routine. Maybe move */
- /* the lock to the caller. */
+ /*
+ * Hold the adapter lock during this routine. Maybe move
+ * the lock to the caller.
+ */
spin_lock(&adapter->AdapterLock);
if (LinkState == adapter->LinkState) {
/* Nothing changed.. */
spin_unlock(&adapter->AdapterLock);
- DBG_ERROR("EXIT #0 %s\n", __func__);
+ DBG_ERROR("EXIT #0 %s. Link status = %d\n",
+ __func__, LinkState);
return;
}
/* Save the adapter state */
@@ -2501,14 +2716,16 @@ static void sxg_link_state(struct adapter_t *adapter, enum SXG_LINK_STATE LinkSt
static int sxg_write_mdio_reg(struct adapter_t *adapter,
u32 DevAddr, u32 RegAddr, u32 Value)
{
- struct SXG_HW_REGS *HwRegs = adapter->HwRegs;
- u32 AddrOp; /* Address operation (written to MIIM field reg) */
- u32 WriteOp; /* Write operation (written to MIIM field reg) */
- u32 Cmd; /* Command (written to MIIM command reg) */
+ struct sxg_hw_regs *HwRegs = adapter->HwRegs;
+ /* Address operation (written to MIIM field reg) */
+ u32 AddrOp;
+ /* Write operation (written to MIIM field reg) */
+ u32 WriteOp;
+ u32 Cmd;/* Command (written to MIIM command reg) */
u32 ValueRead;
u32 Timeout;
-/* DBG_ERROR("ENTER %s\n", __func__); */
+ /* DBG_ERROR("ENTER %s\n", __func__); */
SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "WrtMDIO",
adapter, 0, 0, 0);
@@ -2571,7 +2788,7 @@ static int sxg_write_mdio_reg(struct adapter_t *adapter,
}
} while (ValueRead & AXGMAC_AMIIM_INDC_BUSY);
-/* DBG_ERROR("EXIT %s\n", __func__); */
+ /* DBG_ERROR("EXIT %s\n", __func__); */
return (STATUS_SUCCESS);
}
@@ -2583,7 +2800,7 @@ static int sxg_write_mdio_reg(struct adapter_t *adapter,
* adapter - A pointer to our adapter structure
* DevAddr - MDIO device number being addressed
* RegAddr - register address for the specified MDIO device
- * pValue - pointer to where to put data read from the MDIO register
+ * pValue - pointer to where to put data read from the MDIO register
*
* Return
* status
@@ -2591,16 +2808,16 @@ static int sxg_write_mdio_reg(struct adapter_t *adapter,
static int sxg_read_mdio_reg(struct adapter_t *adapter,
u32 DevAddr, u32 RegAddr, u32 *pValue)
{
- struct SXG_HW_REGS *HwRegs = adapter->HwRegs;
- u32 AddrOp; /* Address operation (written to MIIM field reg) */
- u32 ReadOp; /* Read operation (written to MIIM field reg) */
- u32 Cmd; /* Command (written to MIIM command reg) */
+ struct sxg_hw_regs *HwRegs = adapter->HwRegs;
+ u32 AddrOp; /* Address operation (written to MIIM field reg) */
+ u32 ReadOp; /* Read operation (written to MIIM field reg) */
+ u32 Cmd; /* Command (written to MIIM command reg) */
u32 ValueRead;
u32 Timeout;
SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "WrtMDIO",
adapter, 0, 0, 0);
-/* DBG_ERROR("ENTER %s\n", __func__); */
+ DBG_ERROR("ENTER %s\n", __FUNCTION__);
/* Ensure values don't exceed field width */
DevAddr &= 0x001F; /* 5-bit field */
@@ -2636,6 +2853,8 @@ static int sxg_read_mdio_reg(struct adapter_t *adapter,
udelay(100); /* Timeout in 100us units */
READ_REG(HwRegs->MacAmiimIndicator, ValueRead);
if (--Timeout == 0) {
+ DBG_ERROR("EXIT %s with STATUS_FAILURE 1\n", __FUNCTION__);
+
return (STATUS_FAILURE);
}
} while (ValueRead & AXGMAC_AMIIM_INDC_BUSY);
@@ -2655,6 +2874,8 @@ static int sxg_read_mdio_reg(struct adapter_t *adapter,
udelay(100); /* Timeout in 100us units */
READ_REG(HwRegs->MacAmiimIndicator, ValueRead);
if (--Timeout == 0) {
+ DBG_ERROR("EXIT %s with STATUS_FAILURE 2\n", __FUNCTION__);
+
return (STATUS_FAILURE);
}
} while (ValueRead & AXGMAC_AMIIM_INDC_BUSY);
@@ -2663,7 +2884,7 @@ static int sxg_read_mdio_reg(struct adapter_t *adapter,
READ_REG(HwRegs->MacAmiimField, *pValue);
*pValue &= 0xFFFF; /* data is in the lower 16 bits */
-/* DBG_ERROR("EXIT %s\n", __func__); */
+ DBG_ERROR("EXIT %s\n", __FUNCTION__);
return (STATUS_SUCCESS);
}
@@ -2672,22 +2893,21 @@ static int sxg_read_mdio_reg(struct adapter_t *adapter,
* Functions to obtain the CRC corresponding to the destination mac address.
* This is a standard ethernet CRC in that it is a 32-bit, reflected CRC using
* the polynomial:
- * x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x^1.
- *
- * After the CRC for the 6 bytes is generated (but before the value is complemented),
- * we must then transpose the value and return bits 30-23.
+ * x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^11 + x^10 + x^8 + x^7 + x^5
+ * + x^4 + x^2 + x^1.
*
+ * After the CRC for the 6 bytes is generated (but before the value is
+ * complemented), we must then transpose the value and return bits 30-23.
*/
-static u32 sxg_crc_table[256]; /* Table of CRC's for all possible byte values */
+static u32 sxg_crc_table[256];/* Table of CRC's for all possible byte values */
+static u32 sxg_crc_init; /* Is table initialized */
-/*
- * Contruct the CRC32 table
- */
+/* Contruct the CRC32 table */
static void sxg_mcast_init_crc32(void)
{
- u32 c; /* CRC shit reg */
- u32 e = 0; /* Poly X-or pattern */
- int i; /* counter */
+ u32 c; /* CRC shit reg */
+ u32 e = 0; /* Poly X-or pattern */
+ int i; /* counter */
int k; /* byte being shifted into crc */
static int p[] = { 0, 1, 2, 4, 5, 7, 8, 10, 11, 12, 16, 22, 23, 26 };
@@ -2705,8 +2925,6 @@ static void sxg_mcast_init_crc32(void)
}
}
-#if XXXTODO
-static u32 sxg_crc_init; /* Is table initialized */
/*
* Return the MAC hast as described above.
*/
@@ -2737,25 +2955,31 @@ static unsigned char sxg_mcast_get_mac_hash(char *macaddr)
static void sxg_mcast_set_mask(struct adapter_t *adapter)
{
- struct SXG_UCODE_REGS *sxg_regs = adapter->UcodeRegs;
+ struct sxg_ucode_regs *sxg_regs = adapter->UcodeRegs;
DBG_ERROR("%s ENTER (%s) macopts[%x] mask[%llx]\n", __func__,
adapter->netdev->name, (unsigned int)adapter->MacFilter,
adapter->MulticastMask);
if (adapter->MacFilter & (MAC_ALLMCAST | MAC_PROMISC)) {
- /* Turn on all multicast addresses. We have to do this for promiscuous
- * mode as well as ALLMCAST mode. It saves the Microcode from having
- * to keep state about the MAC configuration.
+ /*
+ * Turn on all multicast addresses. We have to do this for
+ * promiscuous mode as well as ALLMCAST mode. It saves the
+ * Microcode from having keep state about the MAC configuration
+ */
+ /* DBG_ERROR("sxg: %s macopts = MAC_ALLMCAST | MAC_PROMISC\n
+ * SLUT MODE!!!\n",__func__);
*/
-/* DBG_ERROR("sxg: %s macopts = MAC_ALLMCAST | MAC_PROMISC\n SLUT MODE!!!\n",__func__); */
WRITE_REG(sxg_regs->McastLow, 0xFFFFFFFF, FLUSH);
WRITE_REG(sxg_regs->McastHigh, 0xFFFFFFFF, FLUSH);
-/* DBG_ERROR("%s (%s) WRITE to slic_regs slic_mcastlow&high 0xFFFFFFFF\n",__func__, adapter->netdev->name); */
+ /* DBG_ERROR("%s (%s) WRITE to slic_regs slic_mcastlow&high \
+ * 0xFFFFFFFF\n",__func__, adapter->netdev->name);
+ */
} else {
- /* Commit our multicast mast to the SLIC by writing to the multicast
- * address mask registers
+ /*
+ * Commit our multicast mast to the SLIC by writing to the
+ * multicast address mask registers
*/
DBG_ERROR("%s (%s) WRITE mcastlow[%lx] mcasthigh[%lx]\n",
__func__, adapter->netdev->name,
@@ -2777,7 +3001,7 @@ static void sxg_mcast_set_mask(struct adapter_t *adapter)
*/
static int sxg_mcast_add_list(struct adapter_t *adapter, char *address)
{
- p_mcast_address_t mcaddr, mlist;
+ struct mcast_address *mcaddr, *mlist;
bool equaladdr;
/* Check to see if it already exists */
@@ -2791,7 +3015,7 @@ static int sxg_mcast_add_list(struct adapter_t *adapter, char *address)
}
/* Doesn't already exist. Allocate a structure to hold it */
- mcaddr = kmalloc(sizeof(mcast_address_t), GFP_ATOMIC);
+ mcaddr = kmalloc(sizeof(struct mcast_address), GFP_ATOMIC);
if (mcaddr == NULL)
return 1;
@@ -2810,7 +3034,8 @@ static void sxg_mcast_set_bit(struct adapter_t *adapter, char *address)
/* Get the CRC polynomial for the mac address */
crcpoly = sxg_mcast_get_mac_hash(address);
- /* We only have space on the SLIC for 64 entries. Lop
+ /*
+ * We only have space on the SLIC for 64 entries. Lop
* off the top two bits. (2^6 = 64)
*/
crcpoly &= 0x3F;
@@ -2819,74 +3044,79 @@ static void sxg_mcast_set_bit(struct adapter_t *adapter, char *address)
adapter->MulticastMask |= (u64) 1 << crcpoly;
}
-static void sxg_mcast_set_list(p_net_device dev)
+static void sxg_mcast_set_list(struct net_device *dev)
{
struct adapter_t *adapter = (struct adapter_t *) netdev_priv(dev);
- int status = STATUS_SUCCESS;
- int i;
- char *addresses;
- struct dev_mc_list *mc_list = dev->mc_list;
- int mc_count = dev->mc_count;
ASSERT(adapter);
-
- for (i = 1; i <= mc_count; i++) {
- addresses = (char *)&mc_list->dmi_addr;
- if (mc_list->dmi_addrlen == 6) {
- status = sxg_mcast_add_list(adapter, addresses);
- if (status != STATUS_SUCCESS) {
- break;
- }
- } else {
- status = -EINVAL;
- break;
- }
- sxg_mcast_set_bit(adapter, addresses);
- mc_list = mc_list->next;
- }
-
- DBG_ERROR("%s a->devflags_prev[%x] dev->flags[%x] status[%x]\n",
- __func__, adapter->devflags_prev, dev->flags, status);
- if (adapter->devflags_prev != dev->flags) {
- adapter->macopts = MAC_DIRECTED;
- if (dev->flags) {
- if (dev->flags & IFF_BROADCAST) {
- adapter->macopts |= MAC_BCAST;
- }
- if (dev->flags & IFF_PROMISC) {
- adapter->macopts |= MAC_PROMISC;
- }
- if (dev->flags & IFF_ALLMULTI) {
- adapter->macopts |= MAC_ALLMCAST;
- }
- if (dev->flags & IFF_MULTICAST) {
- adapter->macopts |= MAC_MCAST;
- }
- }
- adapter->devflags_prev = dev->flags;
- DBG_ERROR("%s call sxg_config_set adapter->macopts[%x]\n",
- __func__, adapter->macopts);
- sxg_config_set(adapter, TRUE);
- } else {
- if (status == STATUS_SUCCESS) {
- sxg_mcast_set_mask(adapter);
- }
+ if (dev->flags & IFF_PROMISC) {
+ adapter->MacFilter |= MAC_PROMISC;
}
- return;
+ //XXX handle other flags as well
+ sxg_mcast_set_mask(adapter);
}
-#endif
static void sxg_unmap_mmio_space(struct adapter_t *adapter)
{
#if LINUX_FREES_ADAPTER_RESOURCES
-/* if (adapter->Regs) { */
-/* iounmap(adapter->Regs); */
-/* } */
-/* adapter->slic_regs = NULL; */
+/*
+ * if (adapter->Regs) {
+ * iounmap(adapter->Regs);
+ * }
+ * adapter->slic_regs = NULL;
+ */
#endif
}
+/*
+void SxgFreeRcvBlocks(struct adapter_t *adapter)
+{
+ u32 i;
+ struct list_entry *ple;
+ struct sxg_rcv_block_hdr *Hdr;
+ struct sxg_rcv_data_buffer_hdr *RcvDataBufferHdr;
+ u32 FreeBuffers = 0, FreeBlocks = 0;
+
+ SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "FrRcvBlk",
+ adapter, 0, 0, 0);
+
+ ASSERT((adapter->State == SXG_STATE_INITIALIZING) ||
+ (pAdapt->State == SXG_STATE_HALTING));
+
+ for(i = 0; i < SXG_MAX_CPU; i++) {
+ FreeBuffers += pAdapt->PerCpuResources[i].FreeReceiveBuffers.Count;
+ FreeBlocks += pAdapt->PerCpuResources[i].FreeReceiveBlocks.Count;
+ pAdapt->PerCpuResources[i].FreeReceiveBuffers.Count = 0;
+ pAdapt->PerCpuResources[i].FreeReceiveBuffers.FreeList = NULL;
+ pAdapt->PerCpuResources[i].FreeReceiveBlocks.Count = 0;
+ pAdapt->PerCpuResources[i].FreeReceiveBlocks.FreeList = NULL;
+ }
+ FreeBuffers += pAdapt->GlobalResources.FreeReceiveBuffers.Count;
+ FreeBlocks += pAdapt->GlobalResources.FreeReceiveBlocks.Count;
+ pAdapt->GlobalResources.FreeReceiveBuffers.Count = 0;
+ pAdapt->GlobalResources.FreeReceiveBuffers.FreeList = NULL;
+ pAdapt->GlobalResources.FreeReceiveBlocks.Count = 0;
+ pAdapt->GlobalResources.FreeReceiveBlocks.FreeList = NULL;
+ ASSERT(FreeBlocks == pAdapt->AllRcvBlockCount); // See SXG_RCV_BLOCK
+ ASSERT(FreeBuffers ==
+ (pAdapt->AllRcvBlockCount * SXG_RCV_DESCRIPTORS_PER_BLOCK)); // See SXG_RCV_BLOCK
+
+ while(!(IsListEmpty(&pAdapt->AllRcvBlocks))) {
+ ple = RemoveHeadList(&pAdapt->AllRcvBlocks);
+ Hdr = CONTAINING_RECORD(ple, SXG_RCV_BLOCK_HDR, AllList);
+ NdisMFreeSharedMemory(pAdapt->MiniportHandle,
+ SXG_RCV_BLOCK_SIZE(pAdapt->ReceiveBufferSize),
+ TRUE,
+ Hdr->VirtualAddress,
+ Hdr->PhysicalAddress);
+ pAdapt->AllRcvBlockCount--;
+ }
+ ASSERT(pAdapt->AllRcvBlockCount == 0);
+ SLIC_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "XFrRBlk",
+ pAdapt, 0, 0, 0);
+}
+*/
+//#if XXXTODO
-#if XXXTODO
/*
* SxgFreeResources - Free everything allocated in SxgAllocateResources
*
@@ -2899,72 +3129,92 @@ static void sxg_unmap_mmio_space(struct adapter_t *adapter)
void SxgFreeResources(struct adapter_t *adapter)
{
u32 RssIds, IsrCount;
- PTCP_OBJECT TcpObject;
u32 i;
- BOOLEAN TimerCancelled;
-
+/*
SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "FreeRes",
adapter, adapter->MaxTcbs, 0, 0);
-
+*/
RssIds = SXG_RSS_CPU_COUNT(adapter);
IsrCount = adapter->MsiEnabled ? RssIds : 1;
if (adapter->BasicAllocations == FALSE) {
- /* No allocations have been made, including spinlocks, */
- /* or listhead initializations. Return. */
+ /*
+ * No allocations have been made, including spinlocks,
+ * or listhead initializations. Return.
+ */
return;
}
-
+/*
if (!(IsListEmpty(&adapter->AllRcvBlocks))) {
SxgFreeRcvBlocks(adapter);
}
if (!(IsListEmpty(&adapter->AllSglBuffers))) {
SxgFreeSglBuffers(adapter);
}
- /* Free event queues. */
- if (adapter->EventRings) {
- pci_free_consistent(adapter->pcidev,
- sizeof(struct SXG_EVENT_RING) * RssIds,
- adapter->EventRings, adapter->PEventRings);
- }
- if (adapter->Isr) {
- pci_free_consistent(adapter->pcidev,
- sizeof(u32) * IsrCount,
- adapter->Isr, adapter->PIsr);
- }
+*/
+
if (adapter->XmtRingZeroIndex) {
pci_free_consistent(adapter->pcidev,
sizeof(u32),
adapter->XmtRingZeroIndex,
adapter->PXmtRingZeroIndex);
}
- if (adapter->IndirectionTable) {
- pci_free_consistent(adapter->pcidev,
- SXG_MAX_RSS_TABLE_SIZE,
- adapter->IndirectionTable,
- adapter->PIndirectionTable);
- }
+ printk("VSS Free Isr\n");
+ if (adapter->Isr) {
+ pci_free_consistent(adapter->pcidev,
+ sizeof(u32) * IsrCount,
+ adapter->Isr, adapter->PIsr);
+ }
+
+ printk("VSS Free EventRings\n");
+ if (adapter->EventRings) {
+ pci_free_consistent(adapter->pcidev,
+ sizeof(struct sxg_event_ring) * RssIds,
+ adapter->EventRings, adapter->PEventRings);
+ }
+/*
+ printk("VSS Free RcvRings\n");
+ if (adapter->RcvRings) {
+ pci_free_consistent(adapter->pcidev,
+ sizeof(struct sxg_rcv_ring) * 4096,
+ adapter->RcvRings,
+ adapter->PRcvRings);
+ adapter->RcvRings = NULL;
+ }
+
+ printk("VSS Free XmtRings\n");
+ if(adapter->XmtRings) {
+ pci_free_consistent(adapter->pcidev,
+ sizeof(struct sxg_xmt_ring) * 4096,
+ adapter->XmtRings,
+ adapter->PXmtRings);
+ adapter->XmtRings = NULL;
+ }
+
+*/
+
+/*
SXG_FREE_PACKET_POOL(adapter->PacketPoolHandle);
SXG_FREE_BUFFER_POOL(adapter->BufferPoolHandle);
-
+*/
/* Unmap register spaces */
- SxgUnmapResources(adapter);
+ // SxgUnmapResources(adapter);
/* Deregister DMA */
- if (adapter->DmaHandle) {
+/* if (adapter->DmaHandle) {
SXG_DEREGISTER_DMA(adapter->DmaHandle);
}
- /* Deregister interrupt */
- SxgDeregisterInterrupt(adapter);
+*/ /* Deregister interrupt */
+ // SxgDeregisterInterrupt(adapter);
/* Possibly free system info (5.2 only) */
- SXG_RELEASE_SYSTEM_INFO(adapter);
-
- SxgDiagFreeResources(adapter);
+ // SXG_RELEASE_SYSTEM_INFO(adapter);
- SxgFreeMCastAddrs(adapter);
+ //SxgDiagFreeResources(adapter);
+ // SxgFreeMCastAddrs(adapter);
+/*
if (SXG_TIMER_ALLOCATED(adapter->ResetTimer)) {
SXG_CANCEL_TIMER(adapter->ResetTimer, TimerCancelled);
SXG_FREE_TIMER(adapter->ResetTimer);
@@ -2977,13 +3227,14 @@ void SxgFreeResources(struct adapter_t *adapter)
SXG_CANCEL_TIMER(adapter->OffloadTimer, TimerCancelled);
SXG_FREE_TIMER(adapter->OffloadTimer);
}
-
+*/
adapter->BasicAllocations = FALSE;
- SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "XFreeRes",
+/* SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "XFreeRes",
adapter, adapter->MaxTcbs, 0, 0);
+*/
}
-#endif
+// #endif
/*
* sxg_allocate_complete -
@@ -3003,7 +3254,7 @@ void SxgFreeResources(struct adapter_t *adapter)
static void sxg_allocate_complete(struct adapter_t *adapter,
void *VirtualAddress,
dma_addr_t PhysicalAddress,
- u32 Length, enum SXG_BUFFER_TYPE Context)
+ u32 Length, enum sxg_buffer_type Context)
{
SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "AllocCmp",
adapter, VirtualAddress, Length, Context);
@@ -3018,7 +3269,7 @@ static void sxg_allocate_complete(struct adapter_t *adapter,
PhysicalAddress, Length);
break;
case SXG_BUFFER_TYPE_SGL:
- sxg_allocate_sgl_buffer_complete(adapter, (struct SXG_SCATTER_GATHER*)
+ sxg_allocate_sgl_buffer_complete(adapter, (struct sxg_scatter_gather *)
VirtualAddress,
PhysicalAddress, Length);
break;
@@ -3040,7 +3291,7 @@ static void sxg_allocate_complete(struct adapter_t *adapter,
* int
*/
static int sxg_allocate_buffer_memory(struct adapter_t *adapter,
- u32 Size, enum SXG_BUFFER_TYPE BufferType)
+ u32 Size, enum sxg_buffer_type BufferType)
{
int status;
void *Buffer;
@@ -3048,14 +3299,17 @@ static int sxg_allocate_buffer_memory(struct adapter_t *adapter,
SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "AllocMem",
adapter, Size, BufferType, 0);
- /* Grab the adapter lock and check the state. */
- /* If we're in anything other than INITIALIZING or */
- /* RUNNING state, fail. This is to prevent */
- /* allocations in an improper driver state */
+ /*
+ * Grab the adapter lock and check the state. If we're in anything other
+ * than INITIALIZING or RUNNING state, fail. This is to prevent
+ * allocations in an improper driver state
+ */
spin_lock(&adapter->AdapterLock);
- /* Increment the AllocationsPending count while holding */
- /* the lock. Pause processing relies on this */
+ /*
+ * Increment the AllocationsPending count while holding
+ * the lock. Pause processing relies on this
+ */
++adapter->AllocationsPending;
spin_unlock(&adapter->AdapterLock);
@@ -3063,8 +3317,10 @@ static int sxg_allocate_buffer_memory(struct adapter_t *adapter,
Buffer = pci_alloc_consistent(adapter->pcidev, Size, &pBuffer);
if (Buffer == NULL) {
spin_lock(&adapter->AdapterLock);
- /* Decrement the AllocationsPending count while holding */
- /* the lock. Pause processing relies on this */
+ /*
+ * Decrement the AllocationsPending count while holding
+ * the lock. Pause processing relies on this
+ */
--adapter->AllocationsPending;
spin_unlock(&adapter->AdapterLock);
SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "AlcMemF1",
@@ -3080,7 +3336,8 @@ static int sxg_allocate_buffer_memory(struct adapter_t *adapter,
}
/*
- * sxg_allocate_rcvblock_complete - Complete a receive descriptor block allocation
+ * sxg_allocate_rcvblock_complete - Complete a receive descriptor
+ * block allocation
*
* Arguments -
* adapter - A pointer to our adapter structure
@@ -3089,7 +3346,6 @@ static int sxg_allocate_buffer_memory(struct adapter_t *adapter,
* Length - Memory length
*
* Return
- *
*/
static void sxg_allocate_rcvblock_complete(struct adapter_t *adapter,
void *RcvBlock,
@@ -3099,11 +3355,11 @@ static void sxg_allocate_rcvblock_complete(struct adapter_t *adapter,
u32 i;
u32 BufferSize = adapter->ReceiveBufferSize;
u64 Paddr;
- struct SXG_RCV_BLOCK_HDR *RcvBlockHdr;
- unsigned char *RcvDataBuffer;
- struct SXG_RCV_DATA_BUFFER_HDR *RcvDataBufferHdr;
- struct SXG_RCV_DESCRIPTOR_BLOCK *RcvDescriptorBlock;
- struct SXG_RCV_DESCRIPTOR_BLOCK_HDR *RcvDescriptorBlockHdr;
+ void *temp_RcvBlock;
+ struct sxg_rcv_block_hdr *RcvBlockHdr;
+ struct sxg_rcv_data_buffer_hdr *RcvDataBufferHdr;
+ struct sxg_rcv_descriptor_block *RcvDescriptorBlock;
+ struct sxg_rcv_descriptor_block_hdr *RcvDescriptorBlockHdr;
SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "AlRcvBlk",
adapter, RcvBlock, Length, 0);
@@ -3113,42 +3369,33 @@ static void sxg_allocate_rcvblock_complete(struct adapter_t *adapter,
memset(RcvBlock, 0, Length);
ASSERT((BufferSize == SXG_RCV_DATA_BUFFER_SIZE) ||
(BufferSize == SXG_RCV_JUMBO_BUFFER_SIZE));
- ASSERT(Length == SXG_RCV_BLOCK_SIZE(BufferSize));
- /* First, initialize the contained pool of receive data */
- /* buffers. This initialization requires NBL/NB/MDL allocations, */
- /* If any of them fail, free the block and return without */
- /* queueing the shared memory */
- RcvDataBuffer = RcvBlock;
-#if 0
- for (i = 0, Paddr = *PhysicalAddress;
- i < SXG_RCV_DESCRIPTORS_PER_BLOCK;
- i++, Paddr.LowPart += BufferSize, RcvDataBuffer += BufferSize)
-#endif
- for (i = 0, Paddr = PhysicalAddress;
- i < SXG_RCV_DESCRIPTORS_PER_BLOCK;
- i++, Paddr += BufferSize, RcvDataBuffer += BufferSize) {
- /* */
- RcvDataBufferHdr =
- (struct SXG_RCV_DATA_BUFFER_HDR*) (RcvDataBuffer +
- SXG_RCV_DATA_BUFFER_HDR_OFFSET
- (BufferSize));
- RcvDataBufferHdr->VirtualAddress = RcvDataBuffer;
- RcvDataBufferHdr->PhysicalAddress = Paddr;
- RcvDataBufferHdr->State = SXG_BUFFER_UPSTREAM; /* For FREE macro assertion */
- RcvDataBufferHdr->Size =
- SXG_RCV_BUFFER_DATA_SIZE(BufferSize);
-
- SXG_ALLOCATE_RCV_PACKET(adapter, RcvDataBufferHdr);
- if (RcvDataBufferHdr->SxgDumbRcvPacket == NULL)
- goto fail;
+ ASSERT(Length == SXG_RCV_BLOCK_SIZE(SXG_RCV_DATA_HDR_SIZE));
+ /*
+ * First, initialize the contained pool of receive data buffers.
+ * This initialization requires NBL/NB/MDL allocations, if any of them
+ * fail, free the block and return without queueing the shared memory
+ */
+ //RcvDataBuffer = RcvBlock;
+ temp_RcvBlock = RcvBlock;
+ for (i = 0; i < SXG_RCV_DESCRIPTORS_PER_BLOCK;
+ i++, temp_RcvBlock += SXG_RCV_DATA_HDR_SIZE) {
+ RcvDataBufferHdr = (struct sxg_rcv_data_buffer_hdr *)
+ temp_RcvBlock;
+ /* For FREE macro assertion */
+ RcvDataBufferHdr->State = SXG_BUFFER_UPSTREAM;
+ SXG_ALLOCATE_RCV_PACKET(adapter, RcvDataBufferHdr, BufferSize);
+ if (RcvDataBufferHdr->SxgDumbRcvPacket == NULL)
+ goto fail;
- }
+ }
- /* Place this entire block of memory on the AllRcvBlocks queue so it can be */
- /* free later */
- RcvBlockHdr =
- (struct SXG_RCV_BLOCK_HDR*) ((unsigned char *)RcvBlock +
- SXG_RCV_BLOCK_HDR_OFFSET(BufferSize));
+ /*
+ * Place this entire block of memory on the AllRcvBlocks queue so it
+ * can be free later
+ */
+
+ RcvBlockHdr = (struct sxg_rcv_block_hdr *) ((unsigned char *)RcvBlock +
+ SXG_RCV_BLOCK_HDR_OFFSET(SXG_RCV_DATA_HDR_SIZE));
RcvBlockHdr->VirtualAddress = RcvBlock;
RcvBlockHdr->PhysicalAddress = PhysicalAddress;
spin_lock(&adapter->RcvQLock);
@@ -3156,14 +3403,15 @@ static void sxg_allocate_rcvblock_complete(struct adapter_t *adapter,
InsertTailList(&adapter->AllRcvBlocks, &RcvBlockHdr->AllList);
spin_unlock(&adapter->RcvQLock);
- /* Now free the contained receive data buffers that we initialized above */
- RcvDataBuffer = RcvBlock;
+ /* Now free the contained receive data buffers that we
+ * initialized above */
+ temp_RcvBlock = RcvBlock;
for (i = 0, Paddr = PhysicalAddress;
i < SXG_RCV_DESCRIPTORS_PER_BLOCK;
- i++, Paddr += BufferSize, RcvDataBuffer += BufferSize) {
- RcvDataBufferHdr = (struct SXG_RCV_DATA_BUFFER_HDR*) (RcvDataBuffer +
- SXG_RCV_DATA_BUFFER_HDR_OFFSET
- (BufferSize));
+ i++, Paddr += SXG_RCV_DATA_HDR_SIZE,
+ temp_RcvBlock += SXG_RCV_DATA_HDR_SIZE) {
+ RcvDataBufferHdr =
+ (struct sxg_rcv_data_buffer_hdr *)temp_RcvBlock;
spin_lock(&adapter->RcvQLock);
SXG_FREE_RCV_DATA_BUFFER(adapter, RcvDataBufferHdr);
spin_unlock(&adapter->RcvQLock);
@@ -3171,13 +3419,13 @@ static void sxg_allocate_rcvblock_complete(struct adapter_t *adapter,
/* Locate the descriptor block and put it on a separate free queue */
RcvDescriptorBlock =
- (struct SXG_RCV_DESCRIPTOR_BLOCK*) ((unsigned char *)RcvBlock +
+ (struct sxg_rcv_descriptor_block *) ((unsigned char *)RcvBlock +
SXG_RCV_DESCRIPTOR_BLOCK_OFFSET
- (BufferSize));
+ (SXG_RCV_DATA_HDR_SIZE));
RcvDescriptorBlockHdr =
- (struct SXG_RCV_DESCRIPTOR_BLOCK_HDR*) ((unsigned char *)RcvBlock +
+ (struct sxg_rcv_descriptor_block_hdr *) ((unsigned char *)RcvBlock +
SXG_RCV_DESCRIPTOR_BLOCK_HDR_OFFSET
- (BufferSize));
+ (SXG_RCV_DATA_HDR_SIZE));
RcvDescriptorBlockHdr->VirtualAddress = RcvDescriptorBlock;
RcvDescriptorBlockHdr->PhysicalAddress = Paddr;
spin_lock(&adapter->RcvQLock);
@@ -3186,16 +3434,14 @@ static void sxg_allocate_rcvblock_complete(struct adapter_t *adapter,
SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "XAlRBlk",
adapter, RcvBlock, Length, 0);
return;
- fail:
+fail:
/* Free any allocated resources */
if (RcvBlock) {
- RcvDataBuffer = RcvBlock;
+ temp_RcvBlock = RcvBlock;
for (i = 0; i < SXG_RCV_DESCRIPTORS_PER_BLOCK;
- i++, RcvDataBuffer += BufferSize) {
+ i++, temp_RcvBlock += SXG_RCV_DATA_HDR_SIZE) {
RcvDataBufferHdr =
- (struct SXG_RCV_DATA_BUFFER_HDR*) (RcvDataBuffer +
- SXG_RCV_DATA_BUFFER_HDR_OFFSET
- (BufferSize));
+ (struct sxg_rcv_data_buffer_hdr *)temp_RcvBlock;
SXG_FREE_RCV_PACKET(RcvDataBufferHdr);
}
pci_free_consistent(adapter->pcidev,
@@ -3213,15 +3459,14 @@ static void sxg_allocate_rcvblock_complete(struct adapter_t *adapter,
*
* Arguments -
* adapter - A pointer to our adapter structure
- * SxgSgl - SXG_SCATTER_GATHER buffer
+ * SxgSgl - struct sxg_scatter_gather buffer
* PhysicalAddress - Physical address
* Length - Memory length
*
* Return
- *
*/
static void sxg_allocate_sgl_buffer_complete(struct adapter_t *adapter,
- struct SXG_SCATTER_GATHER *SxgSgl,
+ struct sxg_scatter_gather *SxgSgl,
dma_addr_t PhysicalAddress,
u32 Length)
{
@@ -3229,9 +3474,11 @@ static void sxg_allocate_sgl_buffer_complete(struct adapter_t *adapter,
adapter, SxgSgl, Length, 0);
spin_lock(&adapter->SglQLock);
adapter->AllSglBufferCount++;
- memset(SxgSgl, 0, sizeof(struct SXG_SCATTER_GATHER*));
- SxgSgl->PhysicalAddress = PhysicalAddress; /* *PhysicalAddress; */
- SxgSgl->adapter = adapter; /* Initialize backpointer once */
+ memset(SxgSgl, 0, sizeof(struct sxg_scatter_gather));
+ /* *PhysicalAddress; */
+ SxgSgl->PhysicalAddress = PhysicalAddress;
+ /* Initialize backpointer once */
+ SxgSgl->adapter = adapter;
InsertTailList(&adapter->AllSglBuffers, &SxgSgl->AllList);
spin_unlock(&adapter->SglQLock);
SxgSgl->State = SXG_BUFFER_BUSY;
@@ -3240,19 +3487,22 @@ static void sxg_allocate_sgl_buffer_complete(struct adapter_t *adapter,
adapter, SxgSgl, Length, 0);
}
-static unsigned char temp_mac_address[6] =
- { 0x00, 0xab, 0xcd, 0xef, 0x12, 0x69 };
static void sxg_adapter_set_hwaddr(struct adapter_t *adapter)
{
-/* DBG_ERROR ("%s ENTER card->config_set[%x] port[%d] physport[%d] funct#[%d]\n", __func__, */
-/* card->config_set, adapter->port, adapter->physport, adapter->functionnumber); */
-/* */
-/* sxg_dbg_macaddrs(adapter); */
-
- memcpy(adapter->macaddr, temp_mac_address, sizeof(struct SXG_CONFIG_MAC));
-/* DBG_ERROR ("%s AFTER copying from config.macinfo into currmacaddr\n", __func__); */
-/* sxg_dbg_macaddrs(adapter); */
+ /*
+ * DBG_ERROR ("%s ENTER card->config_set[%x] port[%d] physport[%d] \
+ * funct#[%d]\n", __func__, card->config_set,
+ * adapter->port, adapter->physport, adapter->functionnumber);
+ *
+ * sxg_dbg_macaddrs(adapter);
+ */
+ /* DBG_ERROR ("%s AFTER copying from config.macinfo into currmacaddr\n",
+ * __FUNCTION__);
+ */
+
+ /* sxg_dbg_macaddrs(adapter); */
+
if (!(adapter->currmacaddr[0] ||
adapter->currmacaddr[1] ||
adapter->currmacaddr[2] ||
@@ -3262,14 +3512,15 @@ static void sxg_adapter_set_hwaddr(struct adapter_t *adapter)
}
if (adapter->netdev) {
memcpy(adapter->netdev->dev_addr, adapter->currmacaddr, 6);
+ memcpy(adapter->netdev->perm_addr, adapter->currmacaddr, 6);
}
-/* DBG_ERROR ("%s EXIT port %d\n", __func__, adapter->port); */
+ /* DBG_ERROR ("%s EXIT port %d\n", __func__, adapter->port); */
sxg_dbg_macaddrs(adapter);
}
#if XXXTODO
-static int sxg_mac_set_address(p_net_device dev, void *ptr)
+static int sxg_mac_set_address(struct net_device *dev, void *ptr)
{
struct adapter_t *adapter = (struct adapter_t *) netdev_priv(dev);
struct sockaddr *addr = ptr;
@@ -3300,18 +3551,15 @@ static int sxg_mac_set_address(p_net_device dev, void *ptr)
}
#endif
-/*****************************************************************************/
-/************* SXG DRIVER FUNCTIONS (below) ********************************/
-/*****************************************************************************/
-
/*
+ * SXG DRIVER FUNCTIONS (below)
+ *
* sxg_initialize_adapter - Initialize adapter
*
* Arguments -
* adapter - A pointer to our adapter structure
*
- * Return
- * int
+ * Return - int
*/
static int sxg_initialize_adapter(struct adapter_t *adapter)
{
@@ -3325,9 +3573,11 @@ static int sxg_initialize_adapter(struct adapter_t *adapter)
RssIds = 1; /* XXXTODO SXG_RSS_CPU_COUNT(adapter); */
IsrCount = adapter->MsiEnabled ? RssIds : 1;
- /* Sanity check SXG_UCODE_REGS structure definition to */
- /* make sure the length is correct */
- ASSERT(sizeof(struct SXG_UCODE_REGS) == SXG_REGISTER_SIZE_PER_CPU);
+ /*
+ * Sanity check SXG_UCODE_REGS structure definition to
+ * make sure the length is correct
+ */
+ ASSERT(sizeof(struct sxg_ucode_regs) == SXG_REGISTER_SIZE_PER_CPU);
/* Disable interrupts */
SXG_DISABLE_ALL_INTERRUPTS(adapter);
@@ -3375,11 +3625,12 @@ static int sxg_initialize_adapter(struct adapter_t *adapter)
/* Populate the card with receive buffers */
sxg_stock_rcv_buffers(adapter);
- /* Initialize checksum offload capabilities. At the moment */
- /* we always enable IP and TCP receive checksums on the card. */
- /* Depending on the checksum configuration specified by the */
- /* user, we can choose to report or ignore the checksum */
- /* information provided by the card. */
+ /*
+ * Initialize checksum offload capabilities. At the moment we always
+ * enable IP and TCP receive checksums on the card. Depending on the
+ * checksum configuration specified by the user, we can choose to
+ * report or ignore the checksum information provided by the card.
+ */
WRITE_REG(adapter->UcodeRegs[0].ReceiveChecksum,
SXG_RCV_TCP_CSUM_ENABLED | SXG_RCV_IP_CSUM_ENABLED, TRUE);
@@ -3391,10 +3642,13 @@ static int sxg_initialize_adapter(struct adapter_t *adapter)
if (status != STATUS_SUCCESS) {
return (status);
}
- /* Initialize Dead to FALSE. */
- /* SlicCheckForHang or SlicDumpThread will take it from here. */
+ /*
+ * Initialize Dead to FALSE.
+ * SlicCheckForHang or SlicDumpThread will take it from here.
+ */
adapter->Dead = FALSE;
adapter->PingOutstanding = FALSE;
+ adapter->State = SXG_STATE_RUNNING;
SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "XInit",
adapter, 0, 0, 0);
@@ -3413,15 +3667,14 @@ static int sxg_initialize_adapter(struct adapter_t *adapter)
* status
*/
static int sxg_fill_descriptor_block(struct adapter_t *adapter,
- struct SXG_RCV_DESCRIPTOR_BLOCK_HDR
- *RcvDescriptorBlockHdr)
+ struct sxg_rcv_descriptor_block_hdr *RcvDescriptorBlockHdr)
{
u32 i;
- struct SXG_RING_INFO *RcvRingInfo = &adapter->RcvRingZeroInfo;
- struct SXG_RCV_DATA_BUFFER_HDR *RcvDataBufferHdr;
- struct SXG_RCV_DESCRIPTOR_BLOCK *RcvDescriptorBlock;
- struct SXG_CMD *RingDescriptorCmd;
- struct SXG_RCV_RING *RingZero = &adapter->RcvRings[0];
+ struct sxg_ring_info *RcvRingInfo = &adapter->RcvRingZeroInfo;
+ struct sxg_rcv_data_buffer_hdr *RcvDataBufferHdr;
+ struct sxg_rcv_descriptor_block *RcvDescriptorBlock;
+ struct sxg_cmd *RingDescriptorCmd;
+ struct sxg_rcv_ring *RingZero = &adapter->RcvRings[0];
SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "FilBlk",
adapter, adapter->RcvBuffersOnCard,
@@ -3429,8 +3682,10 @@ static int sxg_fill_descriptor_block(struct adapter_t *adapter,
ASSERT(RcvDescriptorBlockHdr);
- /* If we don't have the resources to fill the descriptor block, */
- /* return failure */
+ /*
+ * If we don't have the resources to fill the descriptor block,
+ * return failure
+ */
if ((adapter->FreeRcvBufferCount < SXG_RCV_DESCRIPTORS_PER_BLOCK) ||
SXG_RING_FULL(RcvRingInfo)) {
adapter->Stats.NoMem++;
@@ -3441,27 +3696,31 @@ static int sxg_fill_descriptor_block(struct adapter_t *adapter,
RcvRingInfo, RingDescriptorCmd, RcvDescriptorBlockHdr);
ASSERT(RingDescriptorCmd);
RcvDescriptorBlockHdr->State = SXG_BUFFER_ONCARD;
- RcvDescriptorBlock =
- (struct SXG_RCV_DESCRIPTOR_BLOCK*) RcvDescriptorBlockHdr->VirtualAddress;
+ RcvDescriptorBlock = (struct sxg_rcv_descriptor_block *)
+ RcvDescriptorBlockHdr->VirtualAddress;
/* Fill in the descriptor block */
for (i = 0; i < SXG_RCV_DESCRIPTORS_PER_BLOCK; i++) {
SXG_GET_RCV_DATA_BUFFER(adapter, RcvDataBufferHdr);
ASSERT(RcvDataBufferHdr);
+ ASSERT(RcvDataBufferHdr->SxgDumbRcvPacket);
SXG_REINIATIALIZE_PACKET(RcvDataBufferHdr->SxgDumbRcvPacket);
RcvDataBufferHdr->State = SXG_BUFFER_ONCARD;
RcvDescriptorBlock->Descriptors[i].VirtualAddress =
- (void *)RcvDataBufferHdr;
+ (void *)RcvDataBufferHdr;
+
RcvDescriptorBlock->Descriptors[i].PhysicalAddress =
RcvDataBufferHdr->PhysicalAddress;
}
/* Add the descriptor block to receive descriptor ring 0 */
RingDescriptorCmd->Sgl = RcvDescriptorBlockHdr->PhysicalAddress;
- /* RcvBuffersOnCard is not protected via the receive lock (see */
- /* sxg_process_event_queue) We don't want to grap a lock every time a */
- /* buffer is returned to us, so we use atomic interlocked functions */
- /* instead. */
+ /*
+ * RcvBuffersOnCard is not protected via the receive lock (see
+ * sxg_process_event_queue) We don't want to grap a lock every time a
+ * buffer is returned to us, so we use atomic interlocked functions
+ * instead.
+ */
adapter->RcvBuffersOnCard += SXG_RCV_DESCRIPTORS_PER_BLOCK;
SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "DscBlk",
@@ -3486,34 +3745,36 @@ static int sxg_fill_descriptor_block(struct adapter_t *adapter,
*/
static void sxg_stock_rcv_buffers(struct adapter_t *adapter)
{
- struct SXG_RCV_DESCRIPTOR_BLOCK_HDR *RcvDescriptorBlockHdr;
+ struct sxg_rcv_descriptor_block_hdr *RcvDescriptorBlockHdr;
SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "StockBuf",
adapter, adapter->RcvBuffersOnCard,
adapter->FreeRcvBufferCount, adapter->AllRcvBlockCount);
- /* First, see if we've got less than our minimum threshold of */
- /* receive buffers, there isn't an allocation in progress, and */
- /* we haven't exceeded our maximum.. get another block of buffers */
- /* None of this needs to be SMP safe. It's round numbers. */
+ /*
+ * First, see if we've got less than our minimum threshold of
+ * receive buffers, there isn't an allocation in progress, and
+ * we haven't exceeded our maximum.. get another block of buffers
+ * None of this needs to be SMP safe. It's round numbers.
+ */
if ((adapter->FreeRcvBufferCount < SXG_MIN_RCV_DATA_BUFFERS) &&
(adapter->AllRcvBlockCount < SXG_MAX_RCV_BLOCKS) &&
(adapter->AllocationsPending == 0)) {
sxg_allocate_buffer_memory(adapter,
- SXG_RCV_BLOCK_SIZE(adapter->
- ReceiveBufferSize),
+ SXG_RCV_BLOCK_SIZE
+ (SXG_RCV_DATA_HDR_SIZE),
SXG_BUFFER_TYPE_RCV);
}
/* Now grab the RcvQLock lock and proceed */
spin_lock(&adapter->RcvQLock);
while (adapter->RcvBuffersOnCard < SXG_RCV_DATA_BUFFERS) {
- struct LIST_ENTRY *_ple;
+ struct list_entry *_ple;
/* Get a descriptor block */
RcvDescriptorBlockHdr = NULL;
if (adapter->FreeRcvBlockCount) {
_ple = RemoveHeadList(&adapter->FreeRcvBlocks);
RcvDescriptorBlockHdr =
- container_of(_ple, struct SXG_RCV_DESCRIPTOR_BLOCK_HDR,
+ container_of(_ple, struct sxg_rcv_descriptor_block_hdr,
FreeList);
adapter->FreeRcvBlockCount--;
RcvDescriptorBlockHdr->State = SXG_BUFFER_BUSY;
@@ -3553,10 +3814,10 @@ static void sxg_stock_rcv_buffers(struct adapter_t *adapter)
static void sxg_complete_descriptor_blocks(struct adapter_t *adapter,
unsigned char Index)
{
- struct SXG_RCV_RING *RingZero = &adapter->RcvRings[0];
- struct SXG_RING_INFO *RcvRingInfo = &adapter->RcvRingZeroInfo;
- struct SXG_RCV_DESCRIPTOR_BLOCK_HDR *RcvDescriptorBlockHdr;
- struct SXG_CMD *RingDescriptorCmd;
+ struct sxg_rcv_ring *RingZero = &adapter->RcvRings[0];
+ struct sxg_ring_info *RcvRingInfo = &adapter->RcvRingZeroInfo;
+ struct sxg_rcv_descriptor_block_hdr *RcvDescriptorBlockHdr;
+ struct sxg_cmd *RingDescriptorCmd;
SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "CmpRBlks",
adapter, Index, RcvRingInfo->Head, RcvRingInfo->Tail);
@@ -3565,11 +3826,11 @@ static void sxg_complete_descriptor_blocks(struct adapter_t *adapter,
spin_lock(&adapter->RcvQLock);
ASSERT(Index != RcvRingInfo->Tail);
while (RcvRingInfo->Tail != Index) {
- /* */
- /* Locate the current Cmd (ring descriptor entry), and */
- /* associated receive descriptor block, and advance */
- /* the tail */
- /* */
+ /*
+ * Locate the current Cmd (ring descriptor entry), and
+ * associated receive descriptor block, and advance
+ * the tail
+ */
SXG_RETURN_CMD(RingZero,
RcvRingInfo,
RingDescriptorCmd, RcvDescriptorBlockHdr);
@@ -3579,15 +3840,16 @@ static void sxg_complete_descriptor_blocks(struct adapter_t *adapter,
/* Clear the SGL field */
RingDescriptorCmd->Sgl = 0;
- /* Attempt to refill it and hand it right back to the */
- /* card. If we fail to refill it, free the descriptor block */
- /* header. The card will be restocked later via the */
- /* RcvBuffersOnCard test */
- if (sxg_fill_descriptor_block(adapter, RcvDescriptorBlockHdr) ==
- STATUS_FAILURE) {
+ /*
+ * Attempt to refill it and hand it right back to the
+ * card. If we fail to refill it, free the descriptor block
+ * header. The card will be restocked later via the
+ * RcvBuffersOnCard test
+ */
+ if (sxg_fill_descriptor_block(adapter,
+ RcvDescriptorBlockHdr) == STATUS_FAILURE)
SXG_FREE_RCV_DESCRIPTOR_BLOCK(adapter,
RcvDescriptorBlockHdr);
- }
}
spin_unlock(&adapter->RcvQLock);
SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "XCRBlks",
@@ -3603,7 +3865,7 @@ static struct pci_driver sxg_driver = {
.suspend = sxgpm_suspend,
.resume = sxgpm_resume,
#endif
-/* .shutdown = slic_shutdown, MOOK_INVESTIGATE */
+ /* .shutdown = slic_shutdown, MOOK_INVESTIGATE */
};
static int __init sxg_module_init(void)
diff --git a/drivers/staging/sxg/sxg.h b/drivers/staging/sxg/sxg.h
index 653cf3ba0c4c..28e7cd7337c0 100644
--- a/drivers/staging/sxg/sxg.h
+++ b/drivers/staging/sxg/sxg.h
@@ -43,232 +43,244 @@
#define __SXG_DRIVER_H__
#define p_net_device struct net_device *
-// SXG_STATS - Probably move these to someplace where
-// the slicstat (sxgstat?) program can get them.
-struct SXG_STATS {
- // Xmt
- u32 XmtNBL; // Offload send NBL count
- u64 DumbXmtBytes; // Dumbnic send bytes
- u64 SlowXmtBytes; // Slowpath send bytes
- u64 FastXmtBytes; // Fastpath send bytes
- u64 DumbXmtPkts; // Dumbnic send packets
- u64 SlowXmtPkts; // Slowpath send packets
- u64 FastXmtPkts; // Fastpath send packets
- u64 DumbXmtUcastPkts; // directed packets
- u64 DumbXmtMcastPkts; // Multicast packets
- u64 DumbXmtBcastPkts; // OID_GEN_BROADCAST_FRAMES_RCV
- u64 DumbXmtUcastBytes; // OID_GEN_DIRECTED_BYTES_XMIT
- u64 DumbXmtMcastBytes; // OID_GEN_MULTICAST_BYTES_XMIT
- u64 DumbXmtBcastBytes; // OID_GEN_BROADCAST_BYTES_XMIT
- u64 XmtErrors; // OID_GEN_XMIT_ERROR
- u64 XmtDiscards; // OID_GEN_XMIT_DISCARDS
- u64 XmtOk; // OID_GEN_XMIT_OK
- u64 XmtQLen; // OID_GEN_TRANSMIT_QUEUE_LENGTH
- u64 XmtZeroFull; // Transmit ring zero full
- // Rcv
- u32 RcvNBL; // Offload recieve NBL count
- u64 DumbRcvBytes; // dumbnic recv bytes
- u64 DumbRcvUcastBytes; // OID_GEN_DIRECTED_BYTES_RCV
- u64 DumbRcvMcastBytes; // OID_GEN_MULTICAST_BYTES_RCV
- u64 DumbRcvBcastBytes; // OID_GEN_BROADCAST_BYTES_RCV
- u64 SlowRcvBytes; // Slowpath recv bytes
- u64 FastRcvBytes; // Fastpath recv bytes
- u64 DumbRcvPkts; // OID_GEN_DIRECTED_FRAMES_RCV
- u64 DumbRcvTcpPkts; // See SxgCollectStats
- u64 DumbRcvUcastPkts; // directed packets
- u64 DumbRcvMcastPkts; // Multicast packets
- u64 DumbRcvBcastPkts; // OID_GEN_BROADCAST_FRAMES_RCV
- u64 SlowRcvPkts; // OID_GEN_DIRECTED_FRAMES_RCV
- u64 RcvErrors; // OID_GEN_RCV_ERROR
- u64 RcvDiscards; // OID_GEN_RCV_DISCARDS
- u64 RcvNoBuffer; // OID_GEN_RCV_NO_BUFFER
- u64 PdqFull; // Processed Data Queue Full
- u64 EventRingFull; // Event ring full
- // Verbose stats
- u64 MaxSends; // Max sends outstanding
- u64 NoSglBuf; // SGL buffer allocation failure
- u64 SglFail; // NDIS SGL failure
- u64 SglAsync; // NDIS SGL failure
- u64 NoMem; // Memory allocation failure
- u64 NumInts; // Interrupts
- u64 FalseInts; // Interrupt with ISR == 0
- u64 XmtDrops; // No sahara DRAM buffer for xmt
- // Sahara receive status
- u64 TransportCsum; // SXG_RCV_STATUS_TRANSPORT_CSUM
- u64 TransportUflow; // SXG_RCV_STATUS_TRANSPORT_UFLOW
- u64 TransportHdrLen; // SXG_RCV_STATUS_TRANSPORT_HDRLEN
- u64 NetworkCsum; // SXG_RCV_STATUS_NETWORK_CSUM:
- u64 NetworkUflow; // SXG_RCV_STATUS_NETWORK_UFLOW:
- u64 NetworkHdrLen; // SXG_RCV_STATUS_NETWORK_HDRLEN:
- u64 Parity; // SXG_RCV_STATUS_PARITY
- u64 LinkParity; // SXG_RCV_STATUS_LINK_PARITY:
- u64 LinkEarly; // SXG_RCV_STATUS_LINK_EARLY:
- u64 LinkBufOflow; // SXG_RCV_STATUS_LINK_BUFOFLOW:
- u64 LinkCode; // SXG_RCV_STATUS_LINK_CODE:
- u64 LinkDribble; // SXG_RCV_STATUS_LINK_DRIBBLE:
- u64 LinkCrc; // SXG_RCV_STATUS_LINK_CRC:
- u64 LinkOflow; // SXG_RCV_STATUS_LINK_OFLOW:
- u64 LinkUflow; // SXG_RCV_STATUS_LINK_UFLOW:
+/*
+ * struct sxg_stats - Probably move these to someplace where
+ * the slicstat (sxgstat?) program can get them.
+ */
+struct sxg_stats {
+ /* Xmt */
+ u32 XmtNBL; /* Offload send NBL count */
+ u64 DumbXmtBytes; /* Dumbnic send bytes */
+ u64 SlowXmtBytes; /* Slowpath send bytes */
+ u64 FastXmtBytes; /* Fastpath send bytes */
+ u64 DumbXmtPkts; /* Dumbnic send packets */
+ u64 SlowXmtPkts; /* Slowpath send packets */
+ u64 FastXmtPkts; /* Fastpath send packets */
+ u64 DumbXmtUcastPkts; /* directed packets */
+ u64 DumbXmtMcastPkts; /* Multicast packets */
+ u64 DumbXmtBcastPkts; /* OID_GEN_BROADCAST_FRAMES_RCV */
+ u64 DumbXmtUcastBytes; /* OID_GEN_DIRECTED_BYTES_XMIT */
+ u64 DumbXmtMcastBytes; /* OID_GEN_MULTICAST_BYTES_XMIT */
+ u64 DumbXmtBcastBytes; /* OID_GEN_BROADCAST_BYTES_XMIT */
+ u64 XmtErrors; /* OID_GEN_XMIT_ERROR */
+ u64 XmtDiscards; /* OID_GEN_XMIT_DISCARDS */
+ u64 XmtOk; /* OID_GEN_XMIT_OK */
+ u64 XmtQLen; /* OID_GEN_TRANSMIT_QUEUE_LENGTH */
+ u64 XmtZeroFull; /* Transmit ring zero full */
+ /* Rcv */
+ u32 RcvNBL; /* Offload recieve NBL count */
+ u64 DumbRcvBytes; /* dumbnic recv bytes */
+ u64 DumbRcvUcastBytes; /* OID_GEN_DIRECTED_BYTES_RCV */
+ u64 DumbRcvMcastBytes; /* OID_GEN_MULTICAST_BYTES_RCV */
+ u64 DumbRcvBcastBytes; /* OID_GEN_BROADCAST_BYTES_RCV */
+ u64 SlowRcvBytes; /* Slowpath recv bytes */
+ u64 FastRcvBytes; /* Fastpath recv bytes */
+ u64 DumbRcvPkts; /* OID_GEN_DIRECTED_FRAMES_RCV */
+ u64 DumbRcvTcpPkts; /* See SxgCollectStats */
+ u64 DumbRcvUcastPkts; /* directed packets */
+ u64 DumbRcvMcastPkts; /* Multicast packets */
+ u64 DumbRcvBcastPkts; /* OID_GEN_BROADCAST_FRAMES_RCV */
+ u64 SlowRcvPkts; /* OID_GEN_DIRECTED_FRAMES_RCV */
+ u64 RcvErrors; /* OID_GEN_RCV_ERROR */
+ u64 RcvDiscards; /* OID_GEN_RCV_DISCARDS */
+ u64 RcvNoBuffer; /* OID_GEN_RCV_NO_BUFFER */
+ u64 PdqFull; /* Processed Data Queue Full */
+ u64 EventRingFull; /* Event ring full */
+ /* Verbose stats */
+ u64 MaxSends; /* Max sends outstanding */
+ u64 NoSglBuf; /* SGL buffer allocation failure */
+ u64 SglFail; /* NDIS SGL failure */
+ u64 SglAsync; /* NDIS SGL failure */
+ u64 NoMem; /* Memory allocation failure */
+ u64 NumInts; /* Interrupts */
+ u64 FalseInts; /* Interrupt with ISR == 0 */
+ u64 XmtDrops; /* No sahara DRAM buffer for xmt */
+ /* Sahara receive status */
+ u64 TransportCsum; /* SXG_RCV_STATUS_TRANSPORT_CSUM */
+ u64 TransportUflow; /* SXG_RCV_STATUS_TRANSPORT_UFLOW */
+ u64 TransportHdrLen; /* SXG_RCV_STATUS_TRANSPORT_HDRLEN */
+ u64 NetworkCsum; /* SXG_RCV_STATUS_NETWORK_CSUM: */
+ u64 NetworkUflow; /* SXG_RCV_STATUS_NETWORK_UFLOW: */
+ u64 NetworkHdrLen; /* SXG_RCV_STATUS_NETWORK_HDRLEN: */
+ u64 Parity; /* SXG_RCV_STATUS_PARITY */
+ u64 LinkParity; /* SXG_RCV_STATUS_LINK_PARITY: */
+ u64 LinkEarly; /* SXG_RCV_STATUS_LINK_EARLY: */
+ u64 LinkBufOflow; /* SXG_RCV_STATUS_LINK_BUFOFLOW: */
+ u64 LinkCode; /* SXG_RCV_STATUS_LINK_CODE: */
+ u64 LinkDribble; /* SXG_RCV_STATUS_LINK_DRIBBLE: */
+ u64 LinkCrc; /* SXG_RCV_STATUS_LINK_CRC: */
+ u64 LinkOflow; /* SXG_RCV_STATUS_LINK_OFLOW: */
+ u64 LinkUflow; /* SXG_RCV_STATUS_LINK_UFLOW: */
};
-/****************************************************************************
- * DUMB-NIC Send path definitions
- ****************************************************************************/
+/* DUMB-NIC Send path definitions */
-#define SXG_COMPLETE_DUMB_SEND(_pAdapt, _skb) { \
- ASSERT(_skb); \
- dev_kfree_skb_irq(_skb); \
+#define SXG_COMPLETE_DUMB_SEND(_pAdapt, _skb) { \
+ ASSERT(_skb); \
+ dev_kfree_skb_irq(_skb); \
}
-#define SXG_DROP_DUMB_SEND(_pAdapt, _skb) { \
- ASSERT(_skb); \
- dev_kfree_skb(_skb); \
+#define SXG_DROP_DUMB_SEND(_pAdapt, _skb) { \
+ ASSERT(_skb); \
+ dev_kfree_skb(_skb); \
}
-// Locate current receive header buffer location. Use this
-// instead of RcvDataHdr->VirtualAddress since the data
-// may have been offset by SXG_ADVANCE_MDL_OFFSET
+/*
+ * Locate current receive header buffer location. Use this
+ * instead of RcvDataHdr->VirtualAddress since the data
+ * may have been offset by SXG_ADVANCE_MDL_OFFSET
+ */
#define SXG_RECEIVE_DATA_LOCATION(_RcvDataHdr) (_RcvDataHdr)->skb->data
-/************************************************************************
- * Dumb-NIC receive processing
- ************************************************************************/
-// Define an SXG_PACKET as an NDIS_PACKET
+/* Dumb-NIC receive processing */
+/* Define an SXG_PACKET as an NDIS_PACKET */
#define PSXG_PACKET struct sk_buff *
-// Indications array size
+/* Indications array size */
#define SXG_RCV_ARRAYSIZE 64
-#define SXG_ALLOCATE_RCV_PACKET(_pAdapt, _RcvDataBufferHdr) { \
- struct sk_buff * skb; \
- skb = alloc_skb(2048, GFP_ATOMIC); \
- if (skb) { \
- (_RcvDataBufferHdr)->skb = skb; \
- skb->next = NULL; \
- } else { \
- (_RcvDataBufferHdr)->skb = NULL; \
- } \
+#define SXG_ALLOCATE_RCV_PACKET(_pAdapt, _RcvDataBufferHdr, BufferSize) {\
+ struct sk_buff * skb; \
+ skb = netdev_alloc_skb(_pAdapt->netdev, BufferSize); \
+ if (skb) { \
+ (_RcvDataBufferHdr)->skb = skb; \
+ skb->next = NULL; \
+ _RcvDataBufferHdr->PhysicalAddress = pci_map_single(adapter->pcidev,\
+ _RcvDataBufferHdr->skb->data, BufferSize, PCI_DMA_FROMDEVICE); \
+ } else { \
+ (_RcvDataBufferHdr)->skb = NULL; \
+ } \
}
-#define SXG_FREE_RCV_PACKET(_RcvDataBufferHdr) { \
- if((_RcvDataBufferHdr)->skb) { \
- dev_kfree_skb((_RcvDataBufferHdr)->skb); \
- } \
+#define SXG_FREE_RCV_PACKET(_RcvDataBufferHdr) { \
+ if((_RcvDataBufferHdr)->skb) { \
+ dev_kfree_skb((_RcvDataBufferHdr)->skb); \
+ } \
}
-// Macro to add a NDIS_PACKET to an indication array
-// If we fill up our array of packet pointers, then indicate this
-// block up now and start on a new one.
-#define SXG_ADD_RCV_PACKET(_pAdapt, _Packet, _PrevPacket, _IndicationList, _NumPackets) { \
- (_IndicationList)[_NumPackets] = (_Packet); \
- (_NumPackets)++; \
- if((_NumPackets) == SXG_RCV_ARRAYSIZE) { \
- SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "IndicRcv", \
- (_NumPackets), 0, 0, 0); \
- netif_rx((_IndicationList),(_NumPackets)); \
- (_NumPackets) = 0; \
- } \
+/*
+ * Macro to add a NDIS_PACKET to an indication array
+ * If we fill up our array of packet pointers, then indicate this
+ * block up now and start on a new one.
+ */
+#define SXG_ADD_RCV_PACKET(_pAdapt, _Packet, _PrevPacket, _IndicationList, \
+ _NumPackets) { \
+ (_IndicationList)[_NumPackets] = (_Packet); \
+ (_NumPackets)++; \
+ if((_NumPackets) == SXG_RCV_ARRAYSIZE) { \
+ SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "IndicRcv", \
+ (_NumPackets), 0, 0, 0); \
+ netif_rx((_IndicationList),(_NumPackets)); \
+ (_NumPackets) = 0; \
+ } \
}
-#define SXG_INDICATE_PACKETS(_pAdapt, _IndicationList, _NumPackets) { \
- if(_NumPackets) { \
- SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "IndicRcv", \
- (_NumPackets), 0, 0, 0); \
- netif_rx((_IndicationList),(_NumPackets)); \
- (_NumPackets) = 0; \
- } \
+#define SXG_INDICATE_PACKETS(_pAdapt, _IndicationList, _NumPackets) { \
+ if(_NumPackets) { \
+ SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "IndicRcv", \
+ (_NumPackets), 0, 0, 0); \
+ netif_rx((_IndicationList),(_NumPackets)); \
+ (_NumPackets) = 0; \
+ } \
}
-#define SXG_REINIATIALIZE_PACKET(_Packet) \
- {} /*_NdisReinitializePacket(_Packet)*/ /* this is not necessary with an skb */
+#define SXG_REINIATIALIZE_PACKET(_Packet) \
+ {} /*_NdisReinitializePacket(_Packet)*/
+ /* this is not necessary with an skb */
-// Definitions to initialize Dumb-nic Receive NBLs
-#define SXG_RCV_PACKET_BUFFER_HDR(_Packet) (((PSXG_RCV_NBL_RESERVED)((_Packet)->MiniportReservedEx))->RcvDataBufferHdr)
+/* Definitions to initialize Dumb-nic Receive NBLs */
+#define SXG_RCV_PACKET_BUFFER_HDR(_Packet) (((struct sxg_rcv_nbl_reserved *)\
+ ((_Packet)->MiniportReservedEx))->RcvDataBufferHdr)
-#define SXG_RCV_SET_CHECKSUM_INFO(_Packet, _Cpi) \
- NDIS_PER_PACKET_INFO_FROM_PACKET((_Packet), TcpIpChecksumPacketInfo) = (PVOID)(_Cpi)
+#define SXG_RCV_SET_CHECKSUM_INFO(_Packet, _Cpi) \
+ NDIS_PER_PACKET_INFO_FROM_PACKET((_Packet), \
+ TcpIpChecksumPacketInfo) = (PVOID)(_Cpi)
#define SXG_RCV_SET_TOEPLITZ(_Packet, _Toeplitz, _Type, _Function) { \
- NDIS_PACKET_SET_HASH_VALUE((_Packet), (_Toeplitz)); \
- NDIS_PACKET_SET_HASH_TYPE((_Packet), (_Type)); \
- NDIS_PACKET_SET_HASH_FUNCTION((_Packet), (_Function)); \
+ NDIS_PACKET_SET_HASH_VALUE((_Packet), (_Toeplitz)); \
+ NDIS_PACKET_SET_HASH_TYPE((_Packet), (_Type)); \
+ NDIS_PACKET_SET_HASH_FUNCTION((_Packet), (_Function)); \
}
-#define SXG_RCV_SET_VLAN_INFO(_Packet, _VlanId, _Priority) { \
- NDIS_PACKET_8021Q_INFO _Packet8021qInfo; \
- _Packet8021qInfo.TagHeader.VlanId = (_VlanId); \
- _Packet8021qInfo.TagHeader.UserPriority = (_Priority); \
+#define SXG_RCV_SET_VLAN_INFO(_Packet, _VlanId, _Priority) { \
+ NDIS_PACKET_8021Q_INFO _Packet8021qInfo; \
+ _Packet8021qInfo.TagHeader.VlanId = (_VlanId); \
+ _Packet8021qInfo.TagHeader.UserPriority = (_Priority); \
NDIS_PER_PACKET_INFO_FROM_PACKET((_Packet), Ieee8021QNetBufferListInfo) = \
- _Packet8021qInfo.Value; \
+ _Packet8021qInfo.Value; \
}
-#define SXG_ADJUST_RCV_PACKET(_Packet, _RcvDataBufferHdr, _Event) { \
- SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "DumbRcv", \
- (_RcvDataBufferHdr), (_Packet), \
- (_Event)->Status, 0); \
- ASSERT((_Event)->Length <= (_RcvDataBufferHdr)->Size); \
- Packet->len = (_Event)->Length; \
+#define SXG_ADJUST_RCV_PACKET(_Packet, _RcvDataBufferHdr, _Event) { \
+ SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "DumbRcv", \
+ (_RcvDataBufferHdr), (_Packet), \
+ (_Event)->Status, 0); \
+ /* ASSERT((_Event)->Length <= (_RcvDataBufferHdr)->Size); */ \
+ skb_put(Packet, (_Event)->Length); \
}
-///////////////////////////////////////////////////////////////////////////////
-// Macros to free a receive data buffer and receive data descriptor block
-///////////////////////////////////////////////////////////////////////////////
-// NOTE - Lock must be held with RCV macros
-#define SXG_GET_RCV_DATA_BUFFER(_pAdapt, _Hdr) { \
- struct LIST_ENTRY *_ple; \
- _Hdr = NULL; \
- if((_pAdapt)->FreeRcvBufferCount) { \
- ASSERT(!(IsListEmpty(&(_pAdapt)->FreeRcvBuffers))); \
- _ple = RemoveHeadList(&(_pAdapt)->FreeRcvBuffers); \
- (_Hdr) = container_of(_ple, struct SXG_RCV_DATA_BUFFER_HDR, FreeList); \
- (_pAdapt)->FreeRcvBufferCount--; \
- ASSERT((_Hdr)->State == SXG_BUFFER_FREE); \
- } \
+/*
+ * Macros to free a receive data buffer and receive data descriptor block
+ * NOTE - Lock must be held with RCV macros
+ */
+#define SXG_GET_RCV_DATA_BUFFER(_pAdapt, _Hdr) { \
+ struct list_entry *_ple; \
+ _Hdr = NULL; \
+ if((_pAdapt)->FreeRcvBufferCount) { \
+ ASSERT(!(IsListEmpty(&(_pAdapt)->FreeRcvBuffers))); \
+ _ple = RemoveHeadList(&(_pAdapt)->FreeRcvBuffers); \
+ (_Hdr) = container_of(_ple, struct sxg_rcv_data_buffer_hdr, \
+ FreeList); \
+ (_pAdapt)->FreeRcvBufferCount--; \
+ ASSERT((_Hdr)->State == SXG_BUFFER_FREE); \
+ } \
}
-#define SXG_FREE_RCV_DATA_BUFFER(_pAdapt, _Hdr) { \
- SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "RtnDHdr", \
- (_Hdr), (_pAdapt)->FreeRcvBufferCount, \
- (_Hdr)->State, (_Hdr)->VirtualAddress); \
-/* SXG_RESTORE_MDL_OFFSET(_Hdr); */ \
- (_pAdapt)->FreeRcvBufferCount++; \
- ASSERT(((_pAdapt)->AllRcvBlockCount * SXG_RCV_DESCRIPTORS_PER_BLOCK) >= (_pAdapt)->FreeRcvBufferCount); \
- ASSERT((_Hdr)->State != SXG_BUFFER_FREE); \
- (_Hdr)->State = SXG_BUFFER_FREE; \
- InsertTailList(&(_pAdapt)->FreeRcvBuffers, &((_Hdr)->FreeList)); \
+#define SXG_FREE_RCV_DATA_BUFFER(_pAdapt, _Hdr) { \
+ SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "RtnDHdr", \
+ (_Hdr), (_pAdapt)->FreeRcvBufferCount, \
+ (_Hdr)->State, 0/*(_Hdr)->VirtualAddress*/); \
+/* SXG_RESTORE_MDL_OFFSET(_Hdr); */ \
+ (_pAdapt)->FreeRcvBufferCount++; \
+ ASSERT(((_pAdapt)->AllRcvBlockCount * SXG_RCV_DESCRIPTORS_PER_BLOCK) \
+ >= (_pAdapt)->FreeRcvBufferCount); \
+ ASSERT((_Hdr)->State != SXG_BUFFER_FREE); \
+ (_Hdr)->State = SXG_BUFFER_FREE; \
+ InsertTailList(&(_pAdapt)->FreeRcvBuffers, &((_Hdr)->FreeList)); \
}
-#define SXG_FREE_RCV_DESCRIPTOR_BLOCK(_pAdapt, _Hdr) { \
- ASSERT((_Hdr)->State != SXG_BUFFER_FREE); \
- (_Hdr)->State = SXG_BUFFER_FREE; \
- (_pAdapt)->FreeRcvBlockCount++; \
+#define SXG_FREE_RCV_DESCRIPTOR_BLOCK(_pAdapt, _Hdr) { \
+ ASSERT((_Hdr)->State != SXG_BUFFER_FREE); \
+ (_Hdr)->State = SXG_BUFFER_FREE; \
+ (_pAdapt)->FreeRcvBlockCount++; \
ASSERT((_pAdapt)->AllRcvBlockCount >= (_pAdapt)->FreeRcvBlockCount); \
- InsertTailList(&(_pAdapt)->FreeRcvBlocks, &(_Hdr)->FreeList); \
+ InsertTailList(&(_pAdapt)->FreeRcvBlocks, &(_Hdr)->FreeList); \
}
-// SGL macros
-#define SXG_FREE_SGL_BUFFER(_pAdapt, _Sgl, _NB) { \
- spin_lock(&(_pAdapt)->SglQLock); \
- (_pAdapt)->FreeSglBufferCount++; \
- ASSERT((_pAdapt)->AllSglBufferCount >= (_pAdapt)->FreeSglBufferCount);\
- ASSERT(!((_Sgl)->State & SXG_BUFFER_FREE)); \
- (_Sgl)->State = SXG_BUFFER_FREE; \
- InsertTailList(&(_pAdapt)->FreeSglBuffers, &(_Sgl)->FreeList); \
- spin_unlock(&(_pAdapt)->SglQLock); \
+/* SGL macros */
+#define SXG_FREE_SGL_BUFFER(_pAdapt, _Sgl, _NB) { \
+ spin_lock(&(_pAdapt)->SglQLock); \
+ (_pAdapt)->FreeSglBufferCount++; \
+ ASSERT((_pAdapt)->AllSglBufferCount >= (_pAdapt)->FreeSglBufferCount); \
+ ASSERT(!((_Sgl)->State & SXG_BUFFER_FREE)); \
+ (_Sgl)->State = SXG_BUFFER_FREE; \
+ InsertTailList(&(_pAdapt)->FreeSglBuffers, &(_Sgl)->FreeList); \
+ spin_unlock(&(_pAdapt)->SglQLock); \
}
-// Get an SGL buffer from the free queue. The first part of this macro
-// attempts to keep ahead of buffer depletion by allocating more when
-// we hit a minimum threshold. Note that we don't grab the lock
-// until after that. We're dealing with round numbers here, so we don't need to,
-// and not grabbing it avoids a possible double-trip.
+/*
+ * Get an SGL buffer from the free queue. The first part of this macro
+ * attempts to keep ahead of buffer depletion by allocating more when
+ * we hit a minimum threshold. Note that we don't grab the lock
+ * until after that. We're dealing with round numbers here, so we don't need to,
+ * and not grabbing it avoids a possible double-trip.
+ */
#define SXG_GET_SGL_BUFFER(_pAdapt, _Sgl) { \
- struct LIST_ENTRY *_ple; \
+ struct list_entry *_ple; \
if ((_pAdapt->FreeSglBufferCount < SXG_MIN_SGL_BUFFERS) && \
(_pAdapt->AllSglBufferCount < SXG_MAX_SGL_BUFFERS) && \
(_pAdapt->AllocationsPending == 0)) { \
sxg_allocate_buffer_memory(_pAdapt, \
- (sizeof(struct SXG_SCATTER_GATHER) + SXG_SGL_BUF_SIZE),\
+ (sizeof(struct sxg_scatter_gather) + SXG_SGL_BUF_SIZE),\
SXG_BUFFER_TYPE_SGL); \
} \
_Sgl = NULL; \
@@ -276,7 +288,8 @@ struct SXG_STATS {
if((_pAdapt)->FreeSglBufferCount) { \
ASSERT(!(IsListEmpty(&(_pAdapt)->FreeSglBuffers))); \
_ple = RemoveHeadList(&(_pAdapt)->FreeSglBuffers); \
- (_Sgl) = container_of(_ple, struct SXG_SCATTER_GATHER, FreeList); \
+ (_Sgl) = container_of(_ple, struct sxg_scatter_gather, \
+ FreeList); \
(_pAdapt)->FreeSglBufferCount--; \
ASSERT((_Sgl)->State == SXG_BUFFER_FREE); \
(_Sgl)->State = SXG_BUFFER_BUSY; \
@@ -285,108 +298,113 @@ struct SXG_STATS {
spin_unlock(&(_pAdapt)->SglQLock); \
}
-//
-// SXG_MULTICAST_ADDRESS
-//
-// Linked list of multicast addresses.
-struct SXG_MULTICAST_ADDRESS {
- unsigned char Address[6];
- struct SXG_MULTICAST_ADDRESS *Next;
+/*
+ * struct sxg_multicast_address
+ * Linked list of multicast addresses.
+ */
+struct sxg_multicast_address {
+ unsigned char Address[6];
+ struct sxg_multicast_address *Next;
};
-// Structure to maintain chimney send and receive buffer queues.
-// This structure maintains NET_BUFFER_LIST queues that are
-// given to us via the Chimney MiniportTcpOffloadSend and
-// MiniportTcpOffloadReceive routines. This structure DOES NOT
-// manage our data buffer queue
-struct SXG_BUFFER_QUEUE {
- u32 Type; // Slow or fast - See below
- u32 Direction; // Xmt or Rcv
- u32 Bytes; // Byte count
- u32 * Head; // Send queue head
- u32 * Tail; // Send queue tail
-// PNET_BUFFER_LIST NextNBL; // Short cut - next NBL
-// PNET_BUFFER NextNB; // Short cut - next NB
+/*
+ * Structure to maintain chimney send and receive buffer queues.
+ * This structure maintains NET_BUFFER_LIST queues that are
+ * given to us via the Chimney MiniportTcpOffloadSend and
+ * MiniportTcpOffloadReceive routines. This structure DOES NOT
+ * manage our data buffer queue
+ */
+struct sxg_buffer_queue {
+ u32 Type; /* Slow or fast - See below */
+ u32 Direction; /* Xmt or Rcv */
+ u32 Bytes; /* Byte count */
+ u32 * Head; /* Send queue head */
+ u32 * Tail; /* Send queue tail */
+/* PNET_BUFFER_LIST NextNBL;*/ /* Short cut - next NBL */
+/* PNET_BUFFER NextNB; */ /* Short cut - next NB */
};
#define SXG_SLOW_SEND_BUFFER 0
#define SXG_FAST_SEND_BUFFER 1
#define SXG_RECEIVE_BUFFER 2
-#define SXG_INIT_BUFFER(_Buffer, _Type) { \
- (_Buffer)->Type = (_Type); \
- if((_Type) == SXG_RECEIVE_BUFFER) { \
- (_Buffer)->Direction = 0; \
- } else { \
+#define SXG_INIT_BUFFER(_Buffer, _Type) { \
+ (_Buffer)->Type = (_Type); \
+ if((_Type) == SXG_RECEIVE_BUFFER) { \
+ (_Buffer)->Direction = 0; \
+ } else { \
(_Buffer)->Direction = NDIS_SG_LIST_WRITE_TO_DEVICE; \
- } \
- (_Buffer)->Bytes = 0; \
- (_Buffer)->Head = NULL; \
- (_Buffer)->Tail = NULL; \
+ } \
+ (_Buffer)->Bytes = 0; \
+ (_Buffer)->Head = NULL; \
+ (_Buffer)->Tail = NULL; \
}
-#define SXG_RSS_CPU_COUNT(_pAdapt) \
+#define SXG_RSS_CPU_COUNT(_pAdapt) \
((_pAdapt)->RssEnabled ? NR_CPUS : 1)
-/****************************************************************************
- * DRIVER and ADAPTER structures
- ****************************************************************************/
+/* DRIVER and ADAPTER structures */
-// Adapter states - These states closely match the adapter states
-// documented in the DDK (with a few exceptions).
+/*
+ * Adapter states - These states closely match the adapter states
+ * documented in the DDK (with a few exceptions).
+ */
enum SXG_STATE {
- SXG_STATE_INITIALIZING, // Initializing
- SXG_STATE_BOOTDIAG, // Boot-Diagnostic mode
- SXG_STATE_PAUSING, // Pausing
- SXG_STATE_PAUSED, // Paused
- SXG_STATE_RUNNING, // Running
- SXG_STATE_RESETTING, // Reset in progress
- SXG_STATE_SLEEP, // Sleeping
- SXG_STATE_DIAG, // Diagnostic mode
- SXG_STATE_HALTING, // Halting
- SXG_STATE_HALTED, // Down or not-initialized
- SXG_STATE_SHUTDOWN // shutdown
+ SXG_STATE_INITIALIZING, /* Initializing */
+ SXG_STATE_BOOTDIAG, /* Boot-Diagnostic mode */
+ SXG_STATE_PAUSING, /* Pausing */
+ SXG_STATE_PAUSED, /* Paused */
+ SXG_STATE_RUNNING, /* Running */
+ SXG_STATE_RESETTING, /* Reset in progress */
+ SXG_STATE_SLEEP, /* Sleeping */
+ SXG_STATE_DIAG, /* Diagnostic mode */
+ SXG_STATE_HALTING, /* Halting */
+ SXG_STATE_HALTED, /* Down or not-initialized */
+ SXG_STATE_SHUTDOWN /* shutdown */
};
-// Link state
+/* Link state */
enum SXG_LINK_STATE {
SXG_LINK_DOWN,
SXG_LINK_UP
};
-// Link initialization timeout in 100us units
-#define SXG_LINK_TIMEOUT 100000 // 10 Seconds - REDUCE!
+/* Link initialization timeout in 100us units */
+#define SXG_LINK_TIMEOUT 100000 /* 10 Seconds - REDUCE! */
-// Microcode file selection codes
+/* Microcode file selection codes */
enum SXG_UCODE_SEL {
- SXG_UCODE_SAHARA, // Sahara ucode
- SXG_UCODE_SDIAGCPU, // Sahara CPU diagnostic ucode
- SXG_UCODE_SDIAGSYS // Sahara system diagnostic ucode
+ SXG_UCODE_SAHARA, /* Sahara ucode */
+ SXG_UCODE_SDIAGCPU, /* Sahara CPU diagnostic ucode */
+ SXG_UCODE_SDIAGSYS /* Sahara system diagnostic ucode */
};
#define SXG_DISABLE_ALL_INTERRUPTS(_padapt) sxg_disable_interrupt(_padapt)
#define SXG_ENABLE_ALL_INTERRUPTS(_padapt) sxg_enable_interrupt(_padapt)
-// This probably lives in a proto.h file. Move later
+/* This probably lives in a proto.h file. Move later */
#define SXG_MULTICAST_PACKET(_pether) ((_pether)->ether_dhost[0] & 0x01)
-#define SXG_BROADCAST_PACKET(_pether) ((*(u32 *)(_pether)->ether_dhost == 0xFFFFFFFF) && \
- (*(u16 *)&(_pether)->ether_dhost[4] == 0xFFFF))
+#define SXG_BROADCAST_PACKET(_pether) \
+ ((*(u32 *)(_pether)->ether_dhost == 0xFFFFFFFF) && \
+ (*(u16 *)&(_pether)->ether_dhost[4] == 0xFFFF))
-// For DbgPrints
+/* For DbgPrints */
#define SXG_ID DPFLTR_IHVNETWORK_ID
#define SXG_ERROR DPFLTR_ERROR_LEVEL
-//
-// SXG_DRIVER structure -
-//
-// contains information about the sxg driver. There is only
-// one of these, and it is defined as a global.
-struct SXG_DRIVER {
- struct adapter_t *Adapters; // Linked list of adapters
- ushort AdapterID; // Maintain unique adapter ID
+/*
+ * struct sxg_driver structure -
+ *
+ * contains information about the sxg driver. There is only
+ * one of these, and it is defined as a global.
+ */
+
+struct sxg_driver {
+ struct adapter_t *Adapters; /* Linked list of adapters */
+ ushort AdapterID; /* Maintain unique adapter ID */
};
#ifdef STATUS_SUCCESS
@@ -404,34 +422,36 @@ struct SXG_DRIVER {
#define SLIC_MAX_CARDS 32
#define SLIC_MAX_PORTS 4 /* Max # of ports per card */
#if SLIC_DUMP_ENABLED
-// Dump buffer size
-//
-// This cannot be bigger than the max DMA size the card supports,
-// given the current code structure in the host and ucode.
-// Mojave supports 16K, Oasis supports 16K-1, so
-// just set this at 15K, shouldnt make that much of a diff.
-#define DUMP_BUF_SIZE 0x3C00
+
+/*
+ * Dump buffer size
+ * This cannot be bigger than the max DMA size the card supports,
+ * given the current code structure in the host and ucode.
+ * Mojave supports 16K, Oasis supports 16K-1, so
+ * just set this at 15K, shouldnt make that much of a diff.
+ */
+#define DUMP_BUF_SIZE 0x3C00
#endif
#define MIN(a, b) ((u32)(a) < (u32)(b) ? (a) : (b))
#define MAX(a, b) ((u32)(a) > (u32)(b) ? (a) : (b))
-struct mcast_address_t {
- unsigned char address[6];
- struct mcast_address_t *next;
+struct mcast_address {
+ unsigned char address[6];
+ struct mcast_address *next;
};
-#define CARD_DOWN 0x00000000
-#define CARD_UP 0x00000001
-#define CARD_FAIL 0x00000002
-#define CARD_DIAG 0x00000003
-#define CARD_SLEEP 0x00000004
+#define CARD_DOWN 0x00000000
+#define CARD_UP 0x00000001
+#define CARD_FAIL 0x00000002
+#define CARD_DIAG 0x00000003
+#define CARD_SLEEP 0x00000004
-#define ADAPT_DOWN 0x00
-#define ADAPT_UP 0x01
-#define ADAPT_FAIL 0x02
-#define ADAPT_RESET 0x03
-#define ADAPT_SLEEP 0x04
+#define ADAPT_DOWN 0x00
+#define ADAPT_UP 0x01
+#define ADAPT_FAIL 0x02
+#define ADAPT_RESET 0x03
+#define ADAPT_SLEEP 0x04
#define ADAPT_FLAGS_BOOTTIME 0x0001
#define ADAPT_FLAGS_IS64BIT 0x0002
@@ -443,29 +463,30 @@ struct mcast_address_t {
#define ADAPT_FLAGS_STATS_TIMER_SET 0x0080
#define ADAPT_FLAGS_RESET_TIMER_SET 0x0100
-#define LINK_DOWN 0x00
-#define LINK_CONFIG 0x01
-#define LINK_UP 0x02
+#define LINK_DOWN 0x00
+#define LINK_CONFIG 0x01
+#define LINK_UP 0x02
-#define LINK_10MB 0x00
-#define LINK_100MB 0x01
-#define LINK_AUTOSPEED 0x02
-#define LINK_1000MB 0x03
-#define LINK_10000MB 0x04
+#define LINK_10MB 0x00
+#define LINK_100MB 0x01
+#define LINK_AUTOSPEED 0x02
+#define LINK_1000MB 0x03
+#define LINK_10000MB 0x04
-#define LINK_HALFD 0x00
-#define LINK_FULLD 0x01
-#define LINK_AUTOD 0x02
+#define LINK_HALFD 0x00
+#define LINK_FULLD 0x01
+#define LINK_AUTOD 0x02
-#define MAC_DIRECTED 0x00000001
-#define MAC_BCAST 0x00000002
-#define MAC_MCAST 0x00000004
-#define MAC_PROMISC 0x00000008
-#define MAC_LOOPBACK 0x00000010
-#define MAC_ALLMCAST 0x00000020
+#define MAC_DIRECTED 0x00000001
+#define MAC_BCAST 0x00000002
+#define MAC_MCAST 0x00000004
+#define MAC_PROMISC 0x00000008
+#define MAC_LOOPBACK 0x00000010
+#define MAC_ALLMCAST 0x00000020
#define SLIC_DUPLEX(x) ((x==LINK_FULLD) ? "FDX" : "HDX")
-#define SLIC_SPEED(x) ((x==LINK_100MB) ? "100Mb" : ((x==LINK_1000MB) ? "1000Mb" : " 10Mb"))
+#define SLIC_SPEED(x) ((x==LINK_100MB) ? "100Mb" : \
+ ((x==LINK_1000MB) ? "1000Mb" : " 10Mb"))
#define SLIC_LINKSTATE(x) ((x==LINK_DOWN) ? "Down" : "Up ")
#define SLIC_ADAPTER_STATE(x) ((x==ADAPT_UP) ? "UP" : "Down")
#define SLIC_CARD_STATE(x) ((x==CARD_UP) ? "UP" : "Down")
@@ -481,32 +502,28 @@ struct ether_header {
#define NUM_CFG_SPACES 2
#define NUM_CFG_REGS 64
-struct physcard_t {
- struct adapter_t *adapter[SLIC_MAX_PORTS];
- struct physcard_t *next;
+struct physcard {
+ struct adapter_t *adapter[SLIC_MAX_PORTS];
+ struct physcard *next;
unsigned int adapters_allocd;
};
-struct sxgbase_driver_t {
+struct sxgbase_driver {
spinlock_t driver_lock;
unsigned long flags; /* irqsave for spinlock */
u32 num_sxg_cards;
u32 num_sxg_ports;
u32 num_sxg_ports_active;
u32 dynamic_intagg;
- struct physcard_t *phys_card;
+ struct physcard *phys_card;
};
struct adapter_t {
void * ifp;
unsigned int port;
- struct physcard_t *physcard;
+ struct physcard *physcard;
unsigned int physport;
- unsigned int cardindex;
- unsigned int card_size;
- unsigned int chipid;
- unsigned int busnumber;
unsigned int slotnumber;
unsigned int functionnumber;
ushort vendid;
@@ -514,32 +531,22 @@ struct adapter_t {
ushort subsysid;
u32 irq;
- void * sxg_adapter;
- u32 nBusySend;
-
void __iomem * base_addr;
u32 memorylength;
u32 drambase;
u32 dramlength;
- unsigned int queues_initialized;
- unsigned int allocated;
unsigned int activated;
u32 intrregistered;
unsigned int isp_initialized;
- unsigned int gennumber;
- u32 curaddrupper;
- u32 isrcopy;
unsigned char state;
unsigned char linkstate;
- unsigned char linkspeed;
- unsigned char linkduplex;
unsigned int flags;
unsigned char macaddr[6];
unsigned char currmacaddr[6];
u32 macopts;
ushort devflags_prev;
u64 mcastmask;
- struct mcast_address_t *mcastaddrs;
+ struct mcast_address *mcastaddrs;
struct timer_list pingtimer;
u32 pingtimerset;
struct timer_list statstimer;
@@ -574,135 +581,123 @@ struct adapter_t {
u32 rcv_interrupt_yields;
u32 intagg_period;
struct net_device_stats stats;
- u32 * MiniportHandle; // Our miniport handle
- enum SXG_STATE State; // Adapter state
- enum SXG_LINK_STATE LinkState; // Link state
- u64 LinkSpeed; // Link Speed
- u32 PowerState; // NDIS power state
- struct adapter_t *Next; // Linked list
- ushort AdapterID; // 1..n
- unsigned char MacAddr[6]; // Our permanent HW mac address
- unsigned char CurrMacAddr[6]; // Our Current mac address
- p_net_device netdev;
- p_net_device next_netdevice;
- struct pci_dev * pcidev;
-
- struct SXG_MULTICAST_ADDRESS *MulticastAddrs; // Multicast list
- u64 MulticastMask; // Multicast mask
- u32 * InterruptHandle; // Register Interrupt handle
- u32 InterruptLevel; // From Resource list
- u32 InterruptVector; // From Resource list
- spinlock_t AdapterLock; /* Serialize access adapter routines */
- spinlock_t Bit64RegLock; /* For writing 64-bit addresses */
- struct SXG_HW_REGS *HwRegs; // Sahara HW Register Memory (BAR0/1)
- struct SXG_UCODE_REGS *UcodeRegs; // Microcode Register Memory (BAR2/3)
- struct SXG_TCB_REGS *TcbRegs; // Same as Ucode regs - See sxghw.h
- ushort ResetDpcCount; // For timeout
- ushort RssDpcCount; // For timeout
- ushort VendorID; // Vendor ID
- ushort DeviceID; // Device ID
- ushort SubSystemID; // Sub-System ID
- ushort FrameSize; // Maximum frame size
- u32 * DmaHandle; // NDIS DMA handle
- u32 * PacketPoolHandle; // Used with NDIS 5.2 only. Don't ifdef out
- u32 * BufferPoolHandle; // Used with NDIS 5.2 only. Don't ifdef out
- u32 MacFilter; // NDIS MAC Filter
- ushort IpId; // For slowpath
- struct SXG_EVENT_RING *EventRings; // Host event rings. 1/CPU to 16 max
- dma_addr_t PEventRings; // Physical address
- u32 NextEvent[SXG_MAX_RSS]; // Current location in ring
- dma_addr_t PTcbBuffers; // TCB Buffers - physical address
- dma_addr_t PTcbCompBuffers; // TCB Composite Buffers - phys addr
- struct SXG_XMT_RING *XmtRings; // Transmit rings
- dma_addr_t PXmtRings; // Transmit rings - physical address
- struct SXG_RING_INFO XmtRingZeroInfo; // Transmit ring 0 info
+ u32 * MiniportHandle; /* Our miniport handle */
+ enum SXG_STATE State; /* Adapter state */
+ enum SXG_LINK_STATE LinkState; /* Link state */
+ u64 LinkSpeed; /* Link Speed */
+ u32 PowerState; /* NDIS power state */
+ struct adapter_t *Next; /* Linked list */
+ ushort AdapterID; /* 1..n */
+ struct net_device * netdev;
+ struct net_device * next_netdevice;
+ struct pci_dev *pcidev;
+
+ struct sxg_multicast_address *MulticastAddrs; /* Multicast list */
+ u64 MulticastMask; /* Multicast mask */
+ u32 *InterruptHandle; /* Register Interrupt handle */
+ u32 InterruptLevel; /* From Resource list */
+ u32 InterruptVector; /* From Resource list */
+ spinlock_t AdapterLock; /* Serialize access adapter routines */
+ spinlock_t Bit64RegLock; /* For writing 64-bit addresses */
+ struct sxg_hw_regs *HwRegs; /* Sahara HW Register Memory (BAR0/1) */
+ struct sxg_ucode_regs *UcodeRegs; /* Microcode Register Memory (BAR2/3) */
+ struct sxg_tcb_regs *TcbRegs; /* Same as Ucode regs - See sxghw.h */
+ ushort FrameSize; /* Maximum frame size */
+ u32 * DmaHandle; /* NDIS DMA handle */
+ u32 * PacketPoolHandle; /* Used with NDIS 5.2 only. Don't ifdef out */
+ u32 * BufferPoolHandle; /* Used with NDIS 5.2 only. Don't ifdef out */
+ u32 MacFilter; /* NDIS MAC Filter */
+ struct sxg_event_ring *EventRings; /* Host event rings. 1/CPU to 16 max */
+ dma_addr_t PEventRings; /* Physical address */
+ u32 NextEvent[SXG_MAX_RSS]; /* Current location in ring */
+ dma_addr_t PTcbBuffers; /* TCB Buffers - physical address */
+ dma_addr_t PTcbCompBuffers; /* TCB Composite Buffers - phys addr */
+ struct sxg_xmt_ring *XmtRings; /* Transmit rings */
+ dma_addr_t PXmtRings; /* Transmit rings - physical address */
+ struct sxg_ring_info XmtRingZeroInfo; /* Transmit ring 0 info */
+
spinlock_t XmtZeroLock; /* Transmit ring 0 lock */
- u32 * XmtRingZeroIndex; // Shared XMT ring 0 index
- dma_addr_t PXmtRingZeroIndex; // Shared XMT ring 0 index - physical
- struct LIST_ENTRY FreeProtocolHeaders;// Free protocol headers
- u32 FreeProtoHdrCount; // Count
- void * ProtocolHeaders; // Block of protocol header
- dma_addr_t PProtocolHeaders; // Block of protocol headers - phys
-
- struct SXG_RCV_RING *RcvRings; // Receive rings
- dma_addr_t PRcvRings; // Receive rings - physical address
- struct SXG_RING_INFO RcvRingZeroInfo; // Receive ring 0 info
-
- u32 * Isr; // Interrupt status register
- dma_addr_t PIsr; // ISR - physical address
- u32 IsrCopy[SXG_MAX_RSS]; // Copy of ISR
- ushort InterruptsEnabled; // Bitmask of enabled vectors
- unsigned char * IndirectionTable; // RSS indirection table
- dma_addr_t PIndirectionTable; // Physical address
- ushort RssTableSize; // From NDIS_RECEIVE_SCALE_PARAMETERS
- ushort HashKeySize; // From NDIS_RECEIVE_SCALE_PARAMETERS
- unsigned char HashSecretKey[40]; // rss key
- u32 HashInformation;
- // Receive buffer queues
- spinlock_t RcvQLock; /* Receive Queue Lock */
- struct LIST_ENTRY FreeRcvBuffers; // Free SXG_DATA_BUFFER queue
- struct LIST_ENTRY FreeRcvBlocks; // Free SXG_RCV_DESCRIPTOR_BLOCK Q
- struct LIST_ENTRY AllRcvBlocks; // All SXG_RCV_BLOCKs
- ushort FreeRcvBufferCount; // Number of free rcv data buffers
- ushort FreeRcvBlockCount; // # of free rcv descriptor blocks
- ushort AllRcvBlockCount; // Number of total receive blocks
- ushort ReceiveBufferSize; // SXG_RCV_DATA/JUMBO_BUFFER_SIZE only
- u32 AllocationsPending; // Receive allocation pending
- u32 RcvBuffersOnCard; // SXG_DATA_BUFFERS owned by card
- // SGL buffers
+ u32 * XmtRingZeroIndex; /* Shared XMT ring 0 index */
+ dma_addr_t PXmtRingZeroIndex; /* Shared XMT ring 0 index - physical */
+ struct list_entry FreeProtocolHeaders;/* Free protocol headers */
+ u32 FreeProtoHdrCount; /* Count */
+ void * ProtocolHeaders; /* Block of protocol header */
+ dma_addr_t PProtocolHeaders; /* Block of protocol headers - phys */
+
+ struct sxg_rcv_ring *RcvRings; /* Receive rings */
+ dma_addr_t PRcvRings; /* Receive rings - physical address */
+ struct sxg_ring_info RcvRingZeroInfo; /* Receive ring 0 info */
+
+ u32 * Isr; /* Interrupt status register */
+ dma_addr_t PIsr; /* ISR - physical address */
+ u32 IsrCopy[SXG_MAX_RSS]; /* Copy of ISR */
+ ushort InterruptsEnabled; /* Bitmask of enabled vectors */
+ unsigned char *IndirectionTable; /* RSS indirection table */
+ dma_addr_t PIndirectionTable; /* Physical address */
+ ushort RssTableSize; /* From NDIS_RECEIVE_SCALE_PARAMETERS */
+ ushort HashKeySize; /* From NDIS_RECEIVE_SCALE_PARAMETERS */
+ unsigned char HashSecretKey[40]; /* rss key */
+ u32 HashInformation;
+ /* Receive buffer queues */
+ spinlock_t RcvQLock; /* Receive Queue Lock */
+ struct list_entry FreeRcvBuffers; /* Free SXG_DATA_BUFFER queue */
+ struct list_entry FreeRcvBlocks; /* Free SXG_RCV_DESCRIPTOR_BLOCK Q */
+ struct list_entry AllRcvBlocks; /* All SXG_RCV_BLOCKs */
+ ushort FreeRcvBufferCount; /* Number of free rcv data buffers */
+ ushort FreeRcvBlockCount; /* # of free rcv descriptor blocks */
+ ushort AllRcvBlockCount; /* Number of total receive blocks */
+ ushort ReceiveBufferSize; /* SXG_RCV_DATA/JUMBO_BUFFER_SIZE only */
+ u32 AllocationsPending; /* Receive allocation pending */
+ u32 RcvBuffersOnCard; /* SXG_DATA_BUFFERS owned by card */
+ /* SGL buffers */
spinlock_t SglQLock; /* SGL Queue Lock */
- struct LIST_ENTRY FreeSglBuffers; // Free SXG_SCATTER_GATHER
- struct LIST_ENTRY AllSglBuffers; // All SXG_SCATTER_GATHER
- ushort FreeSglBufferCount; // Number of free SGL buffers
- ushort AllSglBufferCount; // Number of total SGL buffers
- u32 CurrentTime; // Tick count
- u32 FastpathConnections;// # of fastpath connections
- // Various single-bit flags:
- u32 BasicAllocations:1; // Locks and listheads
- u32 IntRegistered:1; // Interrupt registered
- u32 PingOutstanding:1; // Ping outstanding to card
- u32 Dead:1; // Card dead
- u32 DumpDriver:1; // OID_SLIC_DRIVER_DUMP request
- u32 DumpCard:1; // OID_SLIC_CARD_DUMP request
- u32 DumpCmdRunning:1; // Dump command in progress
- u32 DebugRunning:1; // AGDB debug in progress
- u32 JumboEnabled:1; // Jumbo frames enabled
- u32 MsiEnabled:1; // MSI interrupt enabled
- u32 RssEnabled:1; // RSS Enabled
- u32 FailOnBadEeprom:1; // Fail on Bad Eeprom
- u32 DiagStart:1; // Init adapter for diagnostic start
- // Stats
- u32 PendingRcvCount; // Outstanding rcv indications
- u32 PendingXmtCount; // Outstanding send requests
- struct SXG_STATS Stats; // Statistics
- u32 ReassBufs; // Number of reassembly buffers
- // Card Crash Info
- ushort CrashLocation; // Microcode crash location
- unsigned char CrashCpu; // Sahara CPU ID
- // Diagnostics
- // PDIAG_CMD DiagCmds; // List of free diagnostic commands
- // PDIAG_BUFFER DiagBuffers; // List of free diagnostic buffers
- // PDIAG_REQ DiagReqQ; // List of outstanding (asynchronous) diag requests
- // u32 DiagCmdTimeout; // Time out for diag cmds (seconds) XXXTODO - replace with SXG_PARAM var?
- // unsigned char DiagDmaDesc[DMA_CPU_CTXS]; // Free DMA descriptors bit field (32 CPU ctx * 8 DMA ctx)
-
- /////////////////////////////////////////////////////////////////////
- // Put preprocessor-conditional fields at the end so we don't
- // have to recompile sxgdbg everytime we reconfigure the driver
- /////////////////////////////////////////////////////////////////////
- void * PendingSetRss; // Pending RSS parameter change
- u32 IPv4HdrSize; // Shared 5.2/6.0 encap param
- unsigned char * InterruptInfo; // Allocated by us during AddDevice
+ struct list_entry FreeSglBuffers; /* Free struct sxg_scatter_gather */
+ struct list_entry AllSglBuffers; /* All struct sxg_scatter_gather */
+ ushort FreeSglBufferCount; /* Number of free SGL buffers */
+ ushort AllSglBufferCount; /* Number of total SGL buffers */
+ u32 CurrentTime; /* Tick count */
+ u32 FastpathConnections;/* # of fastpath connections */
+ /* Various single-bit flags: */
+ u32 BasicAllocations:1; /* Locks and listheads */
+ u32 IntRegistered:1; /* Interrupt registered */
+ u32 PingOutstanding:1; /* Ping outstanding to card */
+ u32 Dead:1; /* Card dead */
+ u32 DumpDriver:1; /* OID_SLIC_DRIVER_DUMP request */
+ u32 DumpCard:1; /* OID_SLIC_CARD_DUMP request */
+ u32 DumpCmdRunning:1; /* Dump command in progress */
+ u32 DebugRunning:1; /* AGDB debug in progress */
+ u32 JumboEnabled:1; /* Jumbo frames enabled */
+ u32 MsiEnabled:1; /* MSI interrupt enabled */
+ u32 RssEnabled:1; /* RSS Enabled */
+ u32 FailOnBadEeprom:1; /* Fail on Bad Eeprom */
+ u32 DiagStart:1; /* Init adapter for diagnostic start */
+ /* Stats */
+ u32 PendingRcvCount; /* Outstanding rcv indications */
+ u32 PendingXmtCount; /* Outstanding send requests */
+ struct sxg_stats Stats; /* Statistics */
+ u32 ReassBufs; /* Number of reassembly buffers */
+ /* Card Crash Info */
+ ushort CrashLocation; /* Microcode crash location */
+ unsigned char CrashCpu; /* Sahara CPU ID */
+ /* Diagnostics */
+ /* PDIAG_CMD DiagCmds; */ /* List of free diagnostic commands */
+ /* PDIAG_BUFFER DiagBuffers; */ /* List of free diagnostic buffers */
+ /* PDIAG_REQ DiagReqQ; */ /* List of outstanding (asynchronous) diag requests */
+ /* u32 DiagCmdTimeout; */ /* Time out for diag cmds (seconds) XXXTODO - replace with SXG_PARAM var? */
+ /* unsigned char DiagDmaDesc[DMA_CPU_CTXS]; */ /* Free DMA descriptors bit field (32 CPU ctx * 8 DMA ctx) */
+ /*
+ * Put preprocessor-conditional fields at the end so we don't
+ * have to recompile sxgdbg everytime we reconfigure the driver
+ */
#if defined(CONFIG_X86)
- u32 AddrUpper; // Upper 32 bits of 64-bit register
+ u32 AddrUpper; /* Upper 32 bits of 64-bit register */
#endif
- //#if SXG_FAILURE_DUMP
- // NDIS_EVENT DumpThreadEvent; // syncronize dump thread
- // BOOLEAN DumpThreadRunning; // termination flag
- // PSXG_DUMP_CMD DumpBuffer; // 68k - Cmd and Buffer
- // dma_addr_t PDumpBuffer; // Physical address
- //#endif // SXG_FAILURE_DUMP
-
+ /*#if SXG_FAILURE_DUMP */
+ /* NDIS_EVENT DumpThreadEvent; */ /* syncronize dump thread */
+ /* BOOLEAN DumpThreadRunning; */ /* termination flag */
+ /* PSXG_DUMP_CMD DumpBuffer; */ /* 68k - Cmd and Buffer */
+ /* dma_addr_t PDumpBuffer; */ /* Physical address */
+ /*#endif */ /* SXG_FAILURE_DUMP */
};
#if SLIC_DUMP_ENABLED
@@ -710,12 +705,10 @@ struct adapter_t {
#define SLIC_DUMP_IN_PROGRESS 2
#define SLIC_DUMP_DONE 3
-/****************************************************************************
- *
+/*
* Microcode crash information structure. This
* structure is written out to the card's SRAM when the microcode panic's.
- *
- ****************************************************************************/
+ */
struct slic_crash_info {
ushort cpu_id;
ushort crash_pc;
@@ -738,13 +731,13 @@ struct slic_crash_info {
(largestat) += ((newstat) - (oldstat)); \
}
-#define ETHER_EQ_ADDR(_AddrA, _AddrB, _Result) \
-{ \
- _Result = TRUE; \
- if (*(u32 *)(_AddrA) != *(u32 *)(_AddrB)) \
- _Result = FALSE; \
- if (*(u16 *)(&((_AddrA)[4])) != *(u16 *)(&((_AddrB)[4]))) \
- _Result = FALSE; \
+#define ETHER_EQ_ADDR(_AddrA, _AddrB, _Result) \
+{ \
+ _Result = TRUE; \
+ if (*(u32 *)(_AddrA) != *(u32 *)(_AddrB)) \
+ _Result = FALSE; \
+ if (*(u16 *)(&((_AddrA)[4])) != *(u16 *)(&((_AddrB)[4]))) \
+ _Result = FALSE; \
}
#define ETHERMAXFRAME 1514
@@ -752,7 +745,8 @@ struct slic_crash_info {
#if defined(CONFIG_X86_64) || defined(CONFIG_IA64)
#define SXG_GET_ADDR_LOW(_addr) (u32)((u64)(_addr) & 0x00000000FFFFFFFF)
-#define SXG_GET_ADDR_HIGH(_addr) (u32)(((u64)(_addr) >> 32) & 0x00000000FFFFFFFF)
+#define SXG_GET_ADDR_HIGH(_addr) \
+ (u32)(((u64)(_addr) >> 32) & 0x00000000FFFFFFFF)
#else
#define SXG_GET_ADDR_LOW(_addr) (u32)_addr
#define SXG_GET_ADDR_HIGH(_addr) (u32)0
@@ -761,8 +755,8 @@ struct slic_crash_info {
#define FLUSH TRUE
#define DONT_FLUSH FALSE
-#define SIOCSLICDUMPCARD SIOCDEVPRIVATE+9
-#define SIOCSLICSETINTAGG SIOCDEVPRIVATE+10
-#define SIOCSLICTRACEDUMP SIOCDEVPRIVATE+11
+#define SIOCSLICDUMPCARD (SIOCDEVPRIVATE+9)
+#define SIOCSLICSETINTAGG (SIOCDEVPRIVATE+10)
+#define SIOCSLICTRACEDUMP (SIOCDEVPRIVATE+11)
#endif /* __SXG_DRIVER_H__ */
diff --git a/drivers/staging/sxg/sxg_os.h b/drivers/staging/sxg/sxg_os.h
index 6d3f23fb5e1b..68e1a04b61f3 100644
--- a/drivers/staging/sxg/sxg_os.h
+++ b/drivers/staging/sxg/sxg_os.h
@@ -44,34 +44,34 @@
#define FALSE (0)
#define TRUE (1)
-struct LIST_ENTRY {
- struct LIST_ENTRY *nle_flink;
- struct LIST_ENTRY *nle_blink;
+struct list_entry {
+ struct list_entry *nle_flink;
+ struct list_entry *nle_blink;
};
-#define InitializeListHead(l) \
+#define InitializeListHead(l) \
(l)->nle_flink = (l)->nle_blink = (l)
-#define IsListEmpty(h) \
+#define IsListEmpty(h) \
((h)->nle_flink == (h))
-#define RemoveEntryList(e) \
- do { \
- list_entry *b; \
- list_entry *f; \
- \
- f = (e)->nle_flink; \
- b = (e)->nle_blink; \
- b->nle_flink = f; \
- f->nle_blink = b; \
+#define RemoveEntryList(e) \
+ do { \
+ list_entry *b; \
+ list_entry *f; \
+ \
+ f = (e)->nle_flink; \
+ b = (e)->nle_blink; \
+ b->nle_flink = f; \
+ f->nle_blink = b; \
} while (0)
/* These two have to be inlined since they return things. */
-static __inline struct LIST_ENTRY *RemoveHeadList(struct LIST_ENTRY *l)
+static inline struct list_entry *RemoveHeadList(struct list_entry *l)
{
- struct LIST_ENTRY *f;
- struct LIST_ENTRY *e;
+ struct list_entry *f;
+ struct list_entry *e;
e = l->nle_flink;
f = e->nle_flink;
@@ -81,10 +81,10 @@ static __inline struct LIST_ENTRY *RemoveHeadList(struct LIST_ENTRY *l)
return (e);
}
-static __inline struct LIST_ENTRY *RemoveTailList(struct LIST_ENTRY *l)
+static inline struct list_entry *RemoveTailList(struct list_entry *l)
{
- struct LIST_ENTRY *b;
- struct LIST_ENTRY *e;
+ struct list_entry *b;
+ struct list_entry *e;
e = l->nle_blink;
b = e->nle_blink;
@@ -94,54 +94,56 @@ static __inline struct LIST_ENTRY *RemoveTailList(struct LIST_ENTRY *l)
return (e);
}
-#define InsertTailList(l, e) \
- do { \
- struct LIST_ENTRY *b; \
- \
- b = (l)->nle_blink; \
- (e)->nle_flink = (l); \
- (e)->nle_blink = b; \
- b->nle_flink = (e); \
- (l)->nle_blink = (e); \
+#define InsertTailList(l, e) \
+ do { \
+ struct list_entry *b; \
+ \
+ b = (l)->nle_blink; \
+ (e)->nle_flink = (l); \
+ (e)->nle_blink = b; \
+ b->nle_flink = (e); \
+ (l)->nle_blink = (e); \
} while (0)
-#define InsertHeadList(l, e) \
- do { \
- struct LIST_ENTRY *f; \
- \
- f = (l)->nle_flink; \
- (e)->nle_flink = f; \
- (e)->nle_blink = l; \
- f->nle_blink = (e); \
- (l)->nle_flink = (e); \
+#define InsertHeadList(l, e) \
+ do { \
+ struct list_entry *f; \
+ \
+ f = (l)->nle_flink; \
+ (e)->nle_flink = f; \
+ (e)->nle_blink = l; \
+ f->nle_blink = (e); \
+ (l)->nle_flink = (e); \
} while (0)
#define ATK_DEBUG 1
#if ATK_DEBUG
-#define SLIC_TIMESTAMP(value) { \
- struct timeval timev; \
- do_gettimeofday(&timev); \
- value = timev.tv_sec*1000000 + timev.tv_usec; \
+#define SLIC_TIMESTAMP(value) { \
+ struct timeval timev; \
+ do_gettimeofday(&timev); \
+ value = timev.tv_sec*1000000 + timev.tv_usec; \
}
#else
#define SLIC_TIMESTAMP(value)
#endif
-/****************** SXG DEFINES *****************************************/
+/* SXG DEFINES */
#ifdef ATKDBG
-#define SXG_TIMESTAMP(value) { \
- struct timeval timev; \
- do_gettimeofday(&timev); \
- value = timev.tv_sec*1000000 + timev.tv_usec; \
+#define SXG_TIMESTAMP(value) { \
+ struct timeval timev; \
+ do_gettimeofday(&timev); \
+ value = timev.tv_sec*1000000 + timev.tv_usec; \
}
#else
#define SXG_TIMESTAMP(value)
#endif
-#define WRITE_REG(reg,value,flush) sxg_reg32_write((&reg), (value), (flush))
-#define WRITE_REG64(a,reg,value,cpu) sxg_reg64_write((a),(&reg),(value),(cpu))
+#define WRITE_REG(reg,value,flush) \
+ sxg_reg32_write((&reg), (value), (flush))
+#define WRITE_REG64(a,reg,value,cpu) \
+ sxg_reg64_write((a),(&reg),(value),(cpu))
#define READ_REG(reg,value) (value) = readl((void __iomem *)(&reg))
#endif /* _SLIC_OS_SPECIFIC_H_ */
diff --git a/drivers/staging/sxg/sxgdbg.h b/drivers/staging/sxg/sxgdbg.h
index bb58ddf39f30..3f7895c083d4 100644
--- a/drivers/staging/sxg/sxgdbg.h
+++ b/drivers/staging/sxg/sxgdbg.h
@@ -46,20 +46,21 @@
#define ATKDBG 1
#define ATK_TRACE_ENABLED 1
-#define DBG_ERROR(n, args...) printk(KERN_EMERG n, ##args)
+#define DBG_ERROR(n, args...) printk(KERN_WARNING n, ##args)
#ifdef ASSERT
#undef ASSERT
#endif
+#define SXG_ASSERT_ENABLED
#ifdef SXG_ASSERT_ENABLED
#ifndef ASSERT
-#define ASSERT(a) \
- { \
- if (!(a)) { \
- DBG_ERROR("ASSERT() Failure: file %s, function %s line %d\n",\
- __FILE__, __func__, __LINE__); \
- } \
+#define ASSERT(a) \
+ { \
+ if (!(a)) { \
+ DBG_ERROR("ASSERT() Failure: file %s, function %s line %d\n", \
+ __FILE__, __func__, __LINE__); \
+ } \
}
#endif
#else
@@ -78,7 +79,7 @@
extern ulong ATKTimerDiv;
/*
- * trace_entry_t -
+ * trace_entry -
*
* This structure defines an entry in the trace buffer. The
* first few fields mean the same from entry to entry, while
@@ -86,34 +87,34 @@ extern ulong ATKTimerDiv;
* needs of the trace entry. Typically they are function call
* parameters.
*/
-struct trace_entry_t {
- char name[8]; /* 8 character name - like 's'i'm'b'a'r'c'v' */
- u32 time; /* Current clock tic */
- unsigned char cpu; /* Current CPU */
- unsigned char irql; /* Current IRQL */
- unsigned char driver; /* The driver which added the trace call */
- unsigned char pad2; /* pad to 4 byte boundary - will probably get used */
- u32 arg1; /* Caller arg1 */
- u32 arg2; /* Caller arg2 */
- u32 arg3; /* Caller arg3 */
- u32 arg4; /* Caller arg4 */
+struct trace_entry {
+ char name[8];/* 8 character name - like 's'i'm'b'a'r'c'v' */
+ u32 time; /* Current clock tic */
+ unsigned char cpu; /* Current CPU */
+ unsigned char irql; /* Current IRQL */
+ unsigned char driver;/* The driver which added the trace call */
+ /* pad to 4 byte boundary - will probably get used */
+ unsigned char pad2;
+ u32 arg1; /* Caller arg1 */
+ u32 arg2; /* Caller arg2 */
+ u32 arg3; /* Caller arg3 */
+ u32 arg4; /* Caller arg4 */
};
-/*
- * Driver types for driver field in trace_entry_t
- */
+/* Driver types for driver field in struct trace_entry */
#define TRACE_SXG 1
#define TRACE_VPCI 2
#define TRACE_SLIC 3
#define TRACE_ENTRIES 1024
-struct sxg_trace_buffer_t {
- unsigned int size; /* aid for windbg extension */
- unsigned int in; /* Where to add */
- unsigned int level; /* Current Trace level */
- spinlock_t lock; /* For MP tracing */
- struct trace_entry_t entries[TRACE_ENTRIES];/* The circular buffer */
+struct sxg_trace_buffer {
+ /* aid for windbg extension */
+ unsigned int size;
+ unsigned int in; /* Where to add */
+ unsigned int level; /* Current Trace level */
+ spinlock_t lock; /* For MP tracing */
+ struct trace_entry entries[TRACE_ENTRIES];/* The circular buffer */
};
/*
@@ -128,15 +129,11 @@ struct sxg_trace_buffer_t {
#define TRACE_NOISY 10 /* Everything in the world */
-/**********************************************************************
- *
- * The macros themselves -
- *
- *********************************************************************/
+/* The macros themselves */
#if ATK_TRACE_ENABLED
#define SXG_TRACE_INIT(buffer, tlevel) \
{ \
- memset((buffer), 0, sizeof(struct sxg_trace_buffer_t)); \
+ memset((buffer), 0, sizeof(struct sxg_trace_buffer)); \
(buffer)->level = (tlevel); \
(buffer)->size = TRACE_ENTRIES; \
spin_lock_init(&(buffer)->lock); \
@@ -145,27 +142,25 @@ struct sxg_trace_buffer_t {
#define SXG_TRACE_INIT(buffer, tlevel)
#endif
-/*
- * The trace macro. This is active only if ATK_TRACE_ENABLED is set.
- */
+/*The trace macro. This is active only if ATK_TRACE_ENABLED is set. */
#if ATK_TRACE_ENABLED
#define SXG_TRACE(tdriver, buffer, tlevel, tname, a1, a2, a3, a4) { \
- if ((buffer) && ((buffer)->level >= (tlevel))) { \
- unsigned int trace_irql = 0; /* ?????? FIX THIS */ \
- unsigned int trace_len; \
- struct trace_entry_t *trace_entry; \
- struct timeval timev; \
- \
- spin_lock(&(buffer)->lock); \
- trace_entry = &(buffer)->entries[(buffer)->in]; \
- do_gettimeofday(&timev); \
- \
- memset(trace_entry->name, 0, 8); \
- trace_len = strlen(tname); \
- trace_len = trace_len > 8 ? 8 : trace_len; \
- memcpy(trace_entry->name, (tname), trace_len); \
- trace_entry->time = timev.tv_usec; \
- trace_entry->cpu = (unsigned char)(smp_processor_id() & 0xFF); \
+ if ((buffer) && ((buffer)->level >= (tlevel))) { \
+ unsigned int trace_irql = 0;/* ?????? FIX THIS */\
+ unsigned int trace_len; \
+ struct trace_entry *trace_entry; \
+ struct timeval timev; \
+ \
+ spin_lock(&(buffer)->lock); \
+ trace_entry = &(buffer)->entries[(buffer)->in]; \
+ do_gettimeofday(&timev); \
+ \
+ memset(trace_entry->name, 0, 8); \
+ trace_len = strlen(tname); \
+ trace_len = trace_len > 8 ? 8 : trace_len; \
+ memcpy(trace_entry->name, (tname), trace_len); \
+ trace_entry->time = timev.tv_usec; \
+ trace_entry->cpu = (unsigned char)(smp_processor_id() & 0xFF);\
trace_entry->driver = (tdriver); \
trace_entry->irql = trace_irql; \
trace_entry->arg1 = (ulong)(a1); \
diff --git a/drivers/staging/sxg/sxghif.h b/drivers/staging/sxg/sxghif.h
index a4e94685c544..b9e6da9b8ba1 100644
--- a/drivers/staging/sxg/sxghif.h
+++ b/drivers/staging/sxg/sxghif.h
@@ -1,4 +1,4 @@
-/*
+/*******************************************************************
* Copyright © 1997-2007 Alacritech, Inc. All rights reserved
*
* $Id: sxghif.h,v 1.5 2008/07/24 19:18:22 chris Exp $
@@ -7,129 +7,132 @@
*
* This file contains structures and definitions for the
* Alacritech Sahara host interface
- */
-
-/*******************************************************************************
- * UCODE Registers
- *******************************************************************************/
-struct SXG_UCODE_REGS {
- // Address 0 - 0x3F = Command codes 0-15 for TCB 0. Excode 0
- u32 Icr; // Code = 0 (extended), ExCode = 0 - Int control
- u32 RsvdReg1; // Code = 1 - TOE -NA
- u32 RsvdReg2; // Code = 2 - TOE -NA
- u32 RsvdReg3; // Code = 3 - TOE -NA
- u32 RsvdReg4; // Code = 4 - TOE -NA
- u32 RsvdReg5; // Code = 5 - TOE -NA
- u32 CardUp; // Code = 6 - Microcode initialized when 1
- u32 RsvdReg7; // Code = 7 - TOE -NA
- u32 CodeNotUsed[8]; // Codes 8-15 not used. ExCode = 0
- // This brings us to ExCode 1 at address 0x40 = Interrupt status pointer
- u32 Isp; // Code = 0 (extended), ExCode = 1
- u32 PadEx1[15]; // Codes 1-15 not used with extended codes
- // ExCode 2 = Interrupt Status Register
- u32 Isr; // Code = 0 (extended), ExCode = 2
+ ******************************************************************/
+
+/* UCODE Registers */
+struct sxg_ucode_regs {
+ /* Address 0 - 0x3F = Command codes 0-15 for TCB 0. Excode 0 */
+ u32 Icr; /* Code = 0 (extended), ExCode = 0 - Int control */
+ u32 RsvdReg1; /* Code = 1 - TOE -NA */
+ u32 RsvdReg2; /* Code = 2 - TOE -NA */
+ u32 RsvdReg3; /* Code = 3 - TOE -NA */
+ u32 RsvdReg4; /* Code = 4 - TOE -NA */
+ u32 RsvdReg5; /* Code = 5 - TOE -NA */
+ u32 CardUp; /* Code = 6 - Microcode initialized when 1 */
+ u32 RsvdReg7; /* Code = 7 - TOE -NA */
+ u32 ConfigStat; /* Code = 8 - Configuration data load status */
+ u32 RsvdReg9; /* Code = 9 - TOE -NA */
+ u32 CodeNotUsed[6]; /* Codes 10-15 not used. ExCode = 0 */
+ /* This brings us to ExCode 1 at address 0x40 = Interrupt status pointer */
+ u32 Isp; /* Code = 0 (extended), ExCode = 1 */
+ u32 PadEx1[15]; /* Codes 1-15 not used with extended codes */
+ /* ExCode 2 = Interrupt Status Register */
+ u32 Isr; /* Code = 0 (extended), ExCode = 2 */
u32 PadEx2[15];
- // ExCode 3 = Event base register. Location of event rings
- u32 EventBase; // Code = 0 (extended), ExCode = 3
+ /* ExCode 3 = Event base register. Location of event rings */
+ u32 EventBase; /* Code = 0 (extended), ExCode = 3 */
u32 PadEx3[15];
- // ExCode 4 = Event ring size
- u32 EventSize; // Code = 0 (extended), ExCode = 4
+ /* ExCode 4 = Event ring size */
+ u32 EventSize; /* Code = 0 (extended), ExCode = 4 */
u32 PadEx4[15];
- // ExCode 5 = TCB Buffers base address
- u32 TcbBase; // Code = 0 (extended), ExCode = 5
+ /* ExCode 5 = TCB Buffers base address */
+ u32 TcbBase; /* Code = 0 (extended), ExCode = 5 */
u32 PadEx5[15];
- // ExCode 6 = TCB Composite Buffers base address
- u32 TcbCompBase; // Code = 0 (extended), ExCode = 6
+ /* ExCode 6 = TCB Composite Buffers base address */
+ u32 TcbCompBase; /* Code = 0 (extended), ExCode = 6 */
u32 PadEx6[15];
- // ExCode 7 = Transmit ring base address
- u32 XmtBase; // Code = 0 (extended), ExCode = 7
+ /* ExCode 7 = Transmit ring base address */
+ u32 XmtBase; /* Code = 0 (extended), ExCode = 7 */
u32 PadEx7[15];
- // ExCode 8 = Transmit ring size
- u32 XmtSize; // Code = 0 (extended), ExCode = 8
+ /* ExCode 8 = Transmit ring size */
+ u32 XmtSize; /* Code = 0 (extended), ExCode = 8 */
u32 PadEx8[15];
- // ExCode 9 = Receive ring base address
- u32 RcvBase; // Code = 0 (extended), ExCode = 9
+ /* ExCode 9 = Receive ring base address */
+ u32 RcvBase; /* Code = 0 (extended), ExCode = 9 */
u32 PadEx9[15];
- // ExCode 10 = Receive ring size
- u32 RcvSize; // Code = 0 (extended), ExCode = 10
+ /* ExCode 10 = Receive ring size */
+ u32 RcvSize; /* Code = 0 (extended), ExCode = 10 */
u32 PadEx10[15];
- // ExCode 11 = Read EEPROM Config
- u32 Config; // Code = 0 (extended), ExCode = 11
+ /* ExCode 11 = Read EEPROM/Flash Config */
+ u32 Config; /* Code = 0 (extended), ExCode = 11 */
u32 PadEx11[15];
- // ExCode 12 = Multicast bits 31:0
- u32 McastLow; // Code = 0 (extended), ExCode = 12
+ /* ExCode 12 = Multicast bits 31:0 */
+ u32 McastLow; /* Code = 0 (extended), ExCode = 12 */
u32 PadEx12[15];
- // ExCode 13 = Multicast bits 63:32
- u32 McastHigh; // Code = 0 (extended), ExCode = 13
+ /* ExCode 13 = Multicast bits 63:32 */
+ u32 McastHigh; /* Code = 0 (extended), ExCode = 13 */
u32 PadEx13[15];
- // ExCode 14 = Ping
- u32 Ping; // Code = 0 (extended), ExCode = 14
+ /* ExCode 14 = Ping */
+ u32 Ping; /* Code = 0 (extended), ExCode = 14 */
u32 PadEx14[15];
- // ExCode 15 = Link MTU
- u32 LinkMtu; // Code = 0 (extended), ExCode = 15
+ /* ExCode 15 = Link MTU */
+ u32 LinkMtu; /* Code = 0 (extended), ExCode = 15 */
u32 PadEx15[15];
- // ExCode 16 = Download synchronization
- u32 LoadSync; // Code = 0 (extended), ExCode = 16
+ /* ExCode 16 = Download synchronization */
+ u32 LoadSync; /* Code = 0 (extended), ExCode = 16 */
u32 PadEx16[15];
- // ExCode 17 = Upper DRAM address bits on 32-bit systems
- u32 Upper; // Code = 0 (extended), ExCode = 17
+ /* ExCode 17 = Upper DRAM address bits on 32-bit systems */
+ u32 Upper; /* Code = 0 (extended), ExCode = 17 */
u32 PadEx17[15];
- // ExCode 18 = Slowpath Send Index Address
- u32 SPSendIndex; // Code = 0 (extended), ExCode = 18
+ /* ExCode 18 = Slowpath Send Index Address */
+ u32 SPSendIndex; /* Code = 0 (extended), ExCode = 18 */
u32 PadEx18[15];
- u32 RsvdXF; // Code = 0 (extended), ExCode = 19
+ /* ExCode 19 = Get ucode statistics */
+ u32 GetUcodeStats; /* Code = 0 (extended), ExCode = 19 */
u32 PadEx19[15];
- // ExCode 20 = Aggregation
- u32 Aggregation; // Code = 0 (extended), ExCode = 20
+ /* ExCode 20 = Aggregation - See sxgmisc.c:SxgSetInterruptAggregation */
+ u32 Aggregation; /* Code = 0 (extended), ExCode = 20 */
u32 PadEx20[15];
- // ExCode 21 = Receive MDL push timer
- u32 PushTicks; // Code = 0 (extended), ExCode = 21
+ /* ExCode 21 = Receive MDL push timer */
+ u32 PushTicks; /* Code = 0 (extended), ExCode = 21 */
u32 PadEx21[15];
- // ExCode 22 = TOE NA
- u32 AckFrequency; // Code = 0 (extended), ExCode = 22
+ /* ExCode 22 = ACK Frequency */
+ u32 AckFrequency; /* Code = 0 (extended), ExCode = 22 */
u32 PadEx22[15];
- // ExCode 23 = TOE NA
+ /* ExCode 23 = TOE NA */
u32 RsvdReg23;
u32 PadEx23[15];
- // ExCode 24 = TOE NA
+ /* ExCode 24 = TOE NA */
u32 RsvdReg24;
u32 PadEx24[15];
- // ExCode 25 = TOE NA
- u32 RsvdReg25; // Code = 0 (extended), ExCode = 25
+ /* ExCode 25 = TOE NA */
+ u32 RsvdReg25; /* Code = 0 (extended), ExCode = 25 */
u32 PadEx25[15];
- // ExCode 26 = Receive checksum requirements
- u32 ReceiveChecksum; // Code = 0 (extended), ExCode = 26
+ /* ExCode 26 = Receive checksum requirements */
+ u32 ReceiveChecksum; /* Code = 0 (extended), ExCode = 26 */
u32 PadEx26[15];
- // ExCode 27 = RSS Requirements
- u32 Rss; // Code = 0 (extended), ExCode = 27
+ /* ExCode 27 = RSS Requirements */
+ u32 Rss; /* Code = 0 (extended), ExCode = 27 */
u32 PadEx27[15];
- // ExCode 28 = RSS Table
- u32 RssTable; // Code = 0 (extended), ExCode = 28
+ /* ExCode 28 = RSS Table */
+ u32 RssTable; /* Code = 0 (extended), ExCode = 28 */
u32 PadEx28[15];
- // ExCode 29 = Event ring release entries
- u32 EventRelease; // Code = 0 (extended), ExCode = 29
+ /* ExCode 29 = Event ring release entries */
+ u32 EventRelease; /* Code = 0 (extended), ExCode = 29 */
u32 PadEx29[15];
- // ExCode 30 = Number of receive bufferlist commands on ring 0
- u32 RcvCmd; // Code = 0 (extended), ExCode = 30
+ /* ExCode 30 = Number of receive bufferlist commands on ring 0 */
+ u32 RcvCmd; /* Code = 0 (extended), ExCode = 30 */
u32 PadEx30[15];
- // ExCode 31 = slowpath transmit command - Data[31:0] = 1
- u32 XmtCmd; // Code = 0 (extended), ExCode = 31
+ /* ExCode 31 = slowpath transmit command - Data[31:0] = 1 */
+ u32 XmtCmd; /* Code = 0 (extended), ExCode = 31 */
u32 PadEx31[15];
- // ExCode 32 = Dump command
- u32 DumpCmd; // Code = 0 (extended), ExCode = 32
+ /* ExCode 32 = Dump command */
+ u32 DumpCmd; /* Code = 0 (extended), ExCode = 32 */
u32 PadEx32[15];
- // ExCode 33 = Debug command
- u32 DebugCmd; // Code = 0 (extended), ExCode = 33
+ /* ExCode 33 = Debug command */
+ u32 DebugCmd; /* Code = 0 (extended), ExCode = 33 */
u32 PadEx33[15];
- // There are 128 possible extended commands - each of account for 16
- // words (including the non-relevent base command codes 1-15).
- // Pad for the remainder of these here to bring us to the next CPU
- // base. As extended codes are added, reduce the first array value in
- // the following field
- u32 PadToNextCpu[94][16]; // 94 = 128 - 34 (34 = Excodes 0 - 33)
+ /*
+ * There are 128 possible extended commands - each of account for 16
+ * words (including the non-relevent base command codes 1-15).
+ * Pad for the remainder of these here to bring us to the next CPU
+ * base. As extended codes are added, reduce the first array value in
+ * the following field
+ */
+ u32 PadToNextCpu[94][16]; /* 94 = 128 - 34 (34 = Excodes 0 - 33)*/
};
-// Interrupt control register (0) values
+/* Interrupt control register (0) values */
#define SXG_ICR_DISABLE 0x00000000
#define SXG_ICR_ENABLE 0x00000001
#define SXG_ICR_MASK 0x00000002
@@ -139,47 +142,62 @@ struct SXG_UCODE_REGS {
((((_MessageId) << SXG_ICR_MSGID_SHIFT) & \
SXG_ICR_MSGID_MASK) | (_Data))
-// The Microcode supports up to 16 RSS queues
-#define SXG_MAX_RSS 16
-#define SXG_MAX_RSS_TABLE_SIZE 256 // 256-byte max
+#define SXG_MIN_AGG_DEFAULT 0x0010 /* Minimum aggregation default */
+#define SXG_MAX_AGG_DEFAULT 0x0040 /* Maximum aggregation default */
+#define SXG_MAX_AGG_SHIFT 16 /* Maximum in top 16 bits of register */
+/* Disable interrupt aggregation on xmt */
+#define SXG_AGG_XMT_DISABLE 0x80000000
+
+/* The Microcode supports up to 8 RSS queues */
+#define SXG_MAX_RSS 8
+
+#define SXG_MAX_RSS_TABLE_SIZE 256 /* 256-byte max */
+
+#define SXG_RSS_TCP6 0x00000001 /* RSS TCP over IPv6 */
+#define SXG_RSS_TCP4 0x00000002 /* RSS TCP over IPv4 */
+#define SXG_RSS_LEGACY 0x00000004 /* Line-base interrupts */
+#define SXG_RSS_TABLE_SIZE 0x0000FF00 /* Table size mask */
-#define SXG_RSS_TCP6 0x00000001 // RSS TCP over IPv6
-#define SXG_RSS_TCP4 0x00000002 // RSS TCP over IPv4
-#define SXG_RSS_LEGACY 0x00000004 // Line-base interrupts
-#define SXG_RSS_TABLE_SIZE 0x0000FF00 // Table size mask
#define SXG_RSS_TABLE_SHIFT 8
-#define SXG_RSS_BASE_CPU 0x00FF0000 // Base CPU (not used)
+#define SXG_RSS_BASE_CPU 0x00FF0000 /* Base CPU (not used) */
#define SXG_RSS_BASE_SHIFT 16
-#define SXG_RCV_IP_CSUM_ENABLED 0x00000001 // ExCode 26 (ReceiveChecksum)
-#define SXG_RCV_TCP_CSUM_ENABLED 0x00000002 // ExCode 26 (ReceiveChecksum)
+#define SXG_RCV_IP_CSUM_ENABLED 0x00000001 /* ExCode 26 (ReceiveChecksum) */
+#define SXG_RCV_TCP_CSUM_ENABLED 0x00000002 /* ExCode 26 (ReceiveChecksum) */
#define SXG_XMT_CPUID_SHIFT 16
-#if VPCI
-#define SXG_CHECK_FOR_HANG_TIME 3000
-#else
+/*
+ * Status returned by ucode in the ConfigStat reg (see above) when attempted
+ * to load configuration data from the EEPROM/Flash.
+ */
+#define SXG_CFG_TIMEOUT 1 /* init value - timeout if unchanged */
+#define SXG_CFG_LOAD_EEPROM 2 /* config data loaded from EEPROM */
+#define SXG_CFG_LOAD_FLASH 3 /* config data loaded from flash */
+#define SXG_CFG_LOAD_INVALID 4 /* no valid config data found */
+#define SXG_CFG_LOAD_ERROR 5 /* hardware error */
+
#define SXG_CHECK_FOR_HANG_TIME 5
-#endif
/*
* TCB registers - This is really the same register memory area as UCODE_REGS
* above, but defined differently. Bits 17:06 of the address define the TCB,
* which means each TCB area occupies 0x40 (64) bytes, or 16 u32S. What really
* is happening is that these registers occupy the "PadEx[15]" areas in the
- * SXG_UCODE_REGS definition above
+ * struct sxg_ucode_regs definition above
*/
-struct SXG_TCB_REGS {
- u32 ExCode; /* Extended codes - see SXG_UCODE_REGS */
- u32 Xmt; /* Code = 1 - # of Xmt descriptors added to ring */
- u32 Rcv; /* Code = 2 - # of Rcv descriptors added to ring */
- u32 Rsvd1; /* Code = 3 - TOE NA */
- u32 Rsvd2; /* Code = 4 - TOE NA */
- u32 Rsvd3; /* Code = 5 - TOE NA */
- u32 Invalid; /* Code = 6 - Reserved for "CardUp" see above */
- u32 Rsvd4; /* Code = 7 - TOE NA */
- u32 Rsvd5; /* Code = 8 - TOE NA */
- u32 Pad[7]; /* Codes 8-15 - Not used. */
+struct sxg_tcb_regs {
+ u32 ExCode; /* Extended codes - see SXG_UCODE_REGS */
+ u32 Xmt; /* Code = 1 - # of Xmt descriptors added to ring */
+ u32 Rcv; /* Code = 2 - # of Rcv descriptors added to ring */
+ u32 Rsvd1; /* Code = 3 - TOE NA */
+ u32 Rsvd2; /* Code = 4 - TOE NA */
+ u32 Rsvd3; /* Code = 5 - TOE NA */
+ u32 Invalid1; /* Code = 6 - Reserved for "CardUp" see above */
+ u32 Rsvd4; /* Code = 7 - TOE NA */
+ u32 Invalid2; /* Code = 8 - Reserved for "ConfigStat" see above */
+ u32 Rsvd5; /* Code = 9 - TOE NA */
+ u32 Pad[6]; /* Codes 10-15 - Not used. */
};
/***************************************************************************
@@ -206,29 +224,26 @@ struct SXG_TCB_REGS {
* ||---|-CpuId of crash
* |----/
***************************************************************************/
-#define SXG_ISR_ERR 0x80000000 // Error
-#define SXG_ISR_EVENT 0x40000000 // Event ring event
-#define SXG_ISR_NONE1 0x20000000 // Not used
-#define SXG_ISR_UPC 0x10000000 // Dump/debug command complete
-#define SXG_ISR_LINK 0x08000000 // Link event
-#define SXG_ISR_PDQF 0x04000000 // Processed data queue full
-#define SXG_ISR_RMISS 0x02000000 // Drop - no host buf
-#define SXG_ISR_BREAK 0x01000000 // Breakpoint hit
-#define SXG_ISR_PING 0x00800000 // Heartbeat response
-#define SXG_ISR_DEAD 0x00400000 // Card crash
-#define SXG_ISR_ERFULL 0x00200000 // Event ring full
-#define SXG_ISR_XDROP 0x00100000 // XMT Drop - no DRAM bufs or XMT err
-#define SXG_ISR_SPSEND 0x00080000 // Slow send complete
-#define SXG_ISR_CPU 0x00070000 // Dead CPU mask
-#define SXG_ISR_CPU_SHIFT 16 // Dead CPU shift
-#define SXG_ISR_CRASH 0x0000FFFF // Crash address mask
+#define SXG_ISR_ERR 0x80000000 /* Error */
+#define SXG_ISR_EVENT 0x40000000 /* Event ring event */
+#define SXG_ISR_NONE1 0x20000000 /* Not used */
+#define SXG_ISR_UPC 0x10000000 /* Dump/debug command complete*/
+#define SXG_ISR_LINK 0x08000000 /* Link event */
+#define SXG_ISR_PDQF 0x04000000 /* Processed data queue full */
+#define SXG_ISR_RMISS 0x02000000 /* Drop - no host buf */
+#define SXG_ISR_BREAK 0x01000000 /* Breakpoint hit */
+#define SXG_ISR_PING 0x00800000 /* Heartbeat response */
+#define SXG_ISR_DEAD 0x00400000 /* Card crash */
+#define SXG_ISR_ERFULL 0x00200000 /* Event ring full */
+#define SXG_ISR_XDROP 0x00100000 /* XMT Drop - no DRAM bufs or XMT err */
+#define SXG_ISR_SPSEND 0x00080000 /* Slow send complete */
+#define SXG_ISR_CPU 0x00070000 /* Dead CPU mask */
+#define SXG_ISR_CPU_SHIFT 16 /* Dead CPU shift */
+#define SXG_ISR_CRASH 0x0000FFFF /* Crash address mask */
/***************************************************************************
- *
* Event Ring entry
*
- ***************************************************************************/
-/*
* 31 15 0
* .___________________.___________________.
* |<------------ Pad 0 ------------>|
@@ -270,196 +285,208 @@ struct SXG_TCB_REGS {
* ||------- ISTCPIP
* |-------- SCERR
*
- */
+ ************************************************************************/
#pragma pack(push, 1)
-struct SXG_EVENT {
- u32 Pad[1]; // not used
- u32 SndUna; // SndUna value
- u32 Resid; // receive MDL resid
+struct sxg_event {
+ u32 Pad[1]; /* not used */
+ u32 SndUna; /* SndUna value */
+ u32 Resid; /* receive MDL resid */
union {
- void *HostHandle; // Receive host handle
- u32 Rsvd1; // TOE NA
+ void * HostHandle; /* Receive host handle */
+ u32 Rsvd1; /* TOE NA */
struct {
u32 NotUsed;
- u32 Rsvd2; // TOE NA
+ u32 Rsvd2; /* TOE NA */
} Flush;
};
- u32 Toeplitz; // RSS Toeplitz hash
+ u32 Toeplitz; /* RSS Toeplitz hash */
union {
- ushort Rsvd3; // TOE NA
- ushort HdrOffset; // Slowpath
+ ushort Rsvd3; /* TOE NA */
+ ushort HdrOffset; /* Slowpath */
};
- ushort Length; //
- unsigned char Rsvd4; // TOE NA
- unsigned char Code; // Event code
- unsigned char CommandIndex; // New ring index
- unsigned char Status; // Event status
+ ushort Length;
+ unsigned char Rsvd4; /* TOE NA */
+ unsigned char Code; /* Event code */
+ unsigned char CommandIndex; /* New ring index */
+ unsigned char Status; /* Event status */
};
#pragma pack(pop)
-// Event code definitions
-#define EVENT_CODE_BUFFERS 0x01 // Receive buffer list command (ring 0)
-#define EVENT_CODE_SLOWRCV 0x02 // Slowpath receive
-#define EVENT_CODE_UNUSED 0x04 // Was slowpath commands complete
-
-// Status values
-#define EVENT_STATUS_VALID 0x80 // Entry valid
-
-// Slowpath status
-#define EVENT_STATUS_ERROR 0x40 // Completed with error. Index in next byte
-#define EVENT_STATUS_TCPIP4 0x20 // TCPIPv4 frame
-#define EVENT_STATUS_TCPBAD 0x10 // Bad TCP checksum
-#define EVENT_STATUS_IPBAD 0x08 // Bad IP checksum
-#define EVENT_STATUS_RCVERR 0x04 // Slowpath receive error
-#define EVENT_STATUS_IPONLY 0x02 // IP frame
-#define EVENT_STATUS_TCPIP6 0x01 // TCPIPv6 frame
-#define EVENT_STATUS_TCPIP 0x21 // Combination of v4 and v6
-
-// Event ring
-// Size must be power of 2, between 128 and 16k
-#define EVENT_RING_SIZE 4096 // ??
-#define EVENT_RING_BATCH 16 // Hand entries back 16 at a time.
-#define EVENT_BATCH_LIMIT 256 // Stop processing events after 256 (16 * 16)
-
-struct SXG_EVENT_RING {
- struct SXG_EVENT Ring[EVENT_RING_SIZE];
+/* Event code definitions */
+#define EVENT_CODE_BUFFERS 0x01 /* Receive buffer list command (ring 0) */
+#define EVENT_CODE_SLOWRCV 0x02 /* Slowpath receive */
+#define EVENT_CODE_UNUSED 0x04 /* Was slowpath commands complete */
+
+/* Status values */
+#define EVENT_STATUS_VALID 0x80 /* Entry valid */
+
+/* Slowpath status */
+#define EVENT_STATUS_ERROR 0x40 /* Completed with error. Index in next byte */
+#define EVENT_STATUS_TCPIP4 0x20 /* TCPIPv4 frame */
+#define EVENT_STATUS_TCPBAD 0x10 /* Bad TCP checksum */
+#define EVENT_STATUS_IPBAD 0x08 /* Bad IP checksum */
+#define EVENT_STATUS_RCVERR 0x04 /* Slowpath receive error */
+#define EVENT_STATUS_IPONLY 0x02 /* IP frame */
+#define EVENT_STATUS_TCPIP6 0x01 /* TCPIPv6 frame */
+#define EVENT_STATUS_TCPIP 0x21 /* Combination of v4 and v6 */
+
+/*
+ * Event ring
+ * Size must be power of 2, between 128 and 16k
+ */
+#define EVENT_RING_SIZE 4096
+#define EVENT_RING_BATCH 16 /* Hand entries back 16 at a time. */
+/* Stop processing events after 4096 (256 * 16) */
+#define EVENT_BATCH_LIMIT 256
+
+struct sxg_event_ring {
+ struct sxg_event Ring[EVENT_RING_SIZE];
};
-/***************************************************************************
- *
- * TCB Buffers
- *
- ***************************************************************************/
-// Maximum number of TCBS supported by hardware/microcode
+/* TCB Buffers */
+/* Maximum number of TCBS supported by hardware/microcode */
#define SXG_MAX_TCB 4096
-// Minimum TCBs before we fail initialization
+/* Minimum TCBs before we fail initialization */
#define SXG_MIN_TCB 512
-// TCB Hash
-// The bucket is determined by bits 11:4 of the toeplitz if we support 4k
-// offloaded connections, 10:4 if we support 2k and so on.
+/*
+ * TCB Hash
+ * The bucket is determined by bits 11:4 of the toeplitz if we support 4k
+ * offloaded connections, 10:4 if we support 2k and so on.
+ */
#define SXG_TCB_BUCKET_SHIFT 4
-#define SXG_TCB_PER_BUCKET 16
-#define SXG_TCB_BUCKET_MASK 0xFF0 // Bucket portion of TCB ID
-#define SXG_TCB_ELEMENT_MASK 0x00F // Element within bucket
-#define SXG_TCB_BUCKETS 256 // 256 * 16 = 4k
+#define SXG_TCB_PER_BUCKET 16
+#define SXG_TCB_BUCKET_MASK 0xFF0 /* Bucket portion of TCB ID */
+#define SXG_TCB_ELEMENT_MASK 0x00F /* Element within bucket */
+#define SXG_TCB_BUCKETS 256 /* 256 * 16 = 4k */
-#define SXG_TCB_BUFFER_SIZE 512 // ASSERT format is correct
+#define SXG_TCB_BUFFER_SIZE 512 /* ASSERT format is correct */
-#define SXG_TCB_RCVQ_SIZE 736
+#define SXG_TCB_RCVQ_SIZE 736
#define SXG_TCB_COMPOSITE_BUFFER_SIZE 1024
-#define SXG_LOCATE_TCP_FRAME_HDR(_TcpObject, _IPv6) \
- (((_TcpObject)->VlanId) ? \
- ((_IPv6) ? /* Vlan frame header = yes */ \
- &(_TcpObject)->CompBuffer->Frame.HasVlan.TcpIp6.SxgTcp : \
- &(_TcpObject)->CompBuffer->Frame.HasVlan.TcpIp.SxgTcp) : \
- ((_IPv6) ? /* Vlan frame header = No */ \
- &(_TcpObject)->CompBuffer->Frame.NoVlan.TcpIp6.SxgTcp : \
+#define SXG_LOCATE_TCP_FRAME_HDR(_TcpObject, _IPv6) \
+ (((_TcpObject)->VlanId) ? \
+ ((_IPv6) ? /* Vlan frame header = yes */ \
+ &(_TcpObject)->CompBuffer->Frame.HasVlan.TcpIp6.SxgTcp: \
+ &(_TcpObject)->CompBuffer->Frame.HasVlan.TcpIp.SxgTcp): \
+ ((_IPv6) ? /* Vlan frame header = No */ \
+ &(_TcpObject)->CompBuffer->Frame.NoVlan.TcpIp6.SxgTcp : \
&(_TcpObject)->CompBuffer->Frame.NoVlan.TcpIp.SxgTcp))
-#define SXG_LOCATE_IP_FRAME_HDR(_TcpObject) \
- (_TcpObject)->VlanId ? \
- &(_TcpObject)->CompBuffer->Frame.HasVlan.TcpIp.Ip : \
+#define SXG_LOCATE_IP_FRAME_HDR(_TcpObject) \
+ (_TcpObject)->VlanId ? \
+ &(_TcpObject)->CompBuffer->Frame.HasVlan.TcpIp.Ip: \
&(_TcpObject)->CompBuffer->Frame.NoVlan.TcpIp.Ip
-#define SXG_LOCATE_IP6_FRAME_HDR(_TcpObject) \
- (_TcpObject)->VlanId ? \
- &(_TcpObject)->CompBuffer->Frame.HasVlan.TcpIp6.Ip : \
+#define SXG_LOCATE_IP6_FRAME_HDR(TcpObject) \
+ (_TcpObject)->VlanId ? \
+ &(_TcpObject)->CompBuffer->Frame.HasVlan.TcpIp6.Ip: \
&(_TcpObject)->CompBuffer->Frame.NoVlan.TcpIp6.Ip
#if DBG
-// Horrible kludge to distinguish dumb-nic, slowpath, and
-// fastpath traffic. Decrement the HopLimit by one
-// for slowpath, two for fastpath. This assumes the limit is measurably
-// greater than two, which I think is reasonable.
-// Obviously this is DBG only. Maybe remove later, or #if 0 so we
-// can set it when needed
-#define SXG_DBG_HOP_LIMIT(_TcpObject, _FastPath) { \
- PIPV6_HDR _Ip6FrameHdr; \
- if((_TcpObject)->IPv6) { \
- _Ip6FrameHdr = SXG_LOCATE_IP6_FRAME_HDR((_TcpObject)); \
- if(_FastPath) { \
- _Ip6FrameHdr->HopLimit = (_TcpObject)->Cached.TtlOrHopLimit - 2; \
- } else { \
- _Ip6FrameHdr->HopLimit = (_TcpObject)->Cached.TtlOrHopLimit - 1; \
- } \
- } \
+/*
+ * Horrible kludge to distinguish dumb-nic, slowpath, and
+ * fastpath traffic. Decrement the HopLimit by one
+ * for slowpath, two for fastpath. This assumes the limit is measurably
+ * greater than two, which I think is reasonable.
+ * Obviously this is DBG only. Maybe remove later, or #if 0 so we
+ * can set it when needed
+ */
+#define SXG_DBG_HOP_LIMIT(_TcpObject, _FastPath) { \
+ PIPV6_HDR _Ip6FrameHdr; \
+ if ((_TcpObject)->IPv6) { \
+ _Ip6FrameHdr = SXG_LOCATE_IP6_FRAME_HDR((_TcpObject)); \
+ if (_FastPath) { \
+ _Ip6FrameHdr->HopLimit = \
+ (_TcpObject)->Cached.TtlOrHopLimit - 2; \
+ } else { \
+ _Ip6FrameHdr->HopLimit = \
+ (_TcpObject)->Cached.TtlOrHopLimit - 1; \
+ } \
+ } \
}
#else
-// Do nothing with free build
+/* Do nothing with free build */
#define SXG_DBG_HOP_LIMIT(_TcpObject, _FastPath)
#endif
-/***************************************************************************
- * Receive and transmit rings
- ***************************************************************************/
+/* Receive and transmit rings */
#define SXG_MAX_RING_SIZE 256
-#define SXG_XMT_RING_SIZE 128 // Start with 128
-#define SXG_RCV_RING_SIZE 128 // Start with 128
+#define SXG_XMT_RING_SIZE 128 /* Start with 128 */
+#define SXG_RCV_RING_SIZE 128 /* Start with 128 */
#define SXG_MAX_ENTRIES 4096
-// Structure and macros to manage a ring
-struct SXG_RING_INFO {
- unsigned char Head; // Where we add entries - Note unsigned char:RING_SIZE
- unsigned char Tail; // Where we pull off completed entries
- ushort Size; // Ring size - Must be multiple of 2
- void *Context[SXG_MAX_RING_SIZE]; // Shadow ring
+/* Structure and macros to manage a ring */
+struct sxg_ring_info {
+ /* Where we add entries - Note unsigned char:RING_SIZE */
+ unsigned char Head;
+ unsigned char Tail; /* Where we pull off completed entries */
+ ushort Size; /* Ring size - Must be multiple of 2 */
+ void * Context[SXG_MAX_RING_SIZE]; /* Shadow ring */
};
-#define SXG_INITIALIZE_RING(_ring, _size) { \
- (_ring).Head = 0; \
- (_ring).Tail = 0; \
- (_ring).Size = (_size); \
+#define SXG_INITIALIZE_RING(_ring, _size) { \
+ (_ring).Head = 0; \
+ (_ring).Tail = 0; \
+ (_ring).Size = (_size); \
}
-#define SXG_ADVANCE_INDEX(_index, _size) ((_index) = ((_index) + 1) & ((_size) - 1))
-#define SXG_PREVIOUS_INDEX(_index, _size) (((_index) - 1) &((_size) - 1))
+
+#define SXG_ADVANCE_INDEX(_index, _size) \
+ ((_index) = ((_index) + 1) & ((_size) - 1))
+#define SXG_PREVIOUS_INDEX(_index, _size) \
+ (((_index) - 1) &((_size) - 1))
#define SXG_RING_EMPTY(_ring) ((_ring)->Head == (_ring)->Tail)
-#define SXG_RING_FULL(_ring) ((((_ring)->Head + 1) & ((_ring)->Size - 1)) == (_ring)->Tail)
-#define SXG_RING_ADVANCE_HEAD(_ring) SXG_ADVANCE_INDEX((_ring)->Head, ((_ring)->Size))
-#define SXG_RING_RETREAT_HEAD(_ring) ((_ring)->Head = \
- SXG_PREVIOUS_INDEX((_ring)->Head, (_ring)->Size))
-#define SXG_RING_ADVANCE_TAIL(_ring) { \
- ASSERT((_ring)->Tail != (_ring)->Head); \
- SXG_ADVANCE_INDEX((_ring)->Tail, ((_ring)->Size)); \
+#define SXG_RING_FULL(_ring) \
+ ((((_ring)->Head + 1) & ((_ring)->Size - 1)) == (_ring)->Tail)
+#define SXG_RING_ADVANCE_HEAD(_ring) \
+ SXG_ADVANCE_INDEX((_ring)->Head, ((_ring)->Size))
+#define SXG_RING_RETREAT_HEAD(_ring) ((_ring)->Head = \
+ SXG_PREVIOUS_INDEX((_ring)->Head, (_ring)->Size))
+#define SXG_RING_ADVANCE_TAIL(_ring) { \
+ ASSERT((_ring)->Tail != (_ring)->Head); \
+ SXG_ADVANCE_INDEX((_ring)->Tail, ((_ring)->Size)); \
}
-// Set cmd to the next available ring entry, set the shadow context
-// entry and advance the ring.
-// The appropriate lock must be held when calling this macro
-#define SXG_GET_CMD(_ring, _ringinfo, _cmd, _context) { \
- if(SXG_RING_FULL(_ringinfo)) { \
- (_cmd) = NULL; \
- } else { \
- (_cmd) = &(_ring)->Descriptors[(_ringinfo)->Head]; \
+/*
+ * Set cmd to the next available ring entry, set the shadow context
+ * entry and advance the ring.
+ * The appropriate lock must be held when calling this macro
+ */
+#define SXG_GET_CMD(_ring, _ringinfo, _cmd, _context) { \
+ if(SXG_RING_FULL(_ringinfo)) { \
+ (_cmd) = NULL; \
+ } else { \
+ (_cmd) = &(_ring)->Descriptors[(_ringinfo)->Head]; \
(_ringinfo)->Context[(_ringinfo)->Head] = (void *)(_context);\
- SXG_RING_ADVANCE_HEAD(_ringinfo); \
- } \
+ SXG_RING_ADVANCE_HEAD(_ringinfo); \
+ } \
}
-// Abort the previously allocated command by retreating the head.
-// NOTE - The appopriate lock MUST NOT BE DROPPED between the SXG_GET_CMD
-// and SXG_ABORT_CMD calls.
-#define SXG_ABORT_CMD(_ringinfo) { \
- ASSERT(!(SXG_RING_EMPTY(_ringinfo))); \
- SXG_RING_RETREAT_HEAD(_ringinfo); \
- (_ringinfo)->Context[(_ringinfo)->Head] = NULL; \
+/*
+ * Abort the previously allocated command by retreating the head.
+ * NOTE - The appopriate lock MUST NOT BE DROPPED between the SXG_GET_CMD
+ * and SXG_ABORT_CMD calls.
+ */
+#define SXG_ABORT_CMD(_ringinfo) { \
+ ASSERT(!(SXG_RING_EMPTY(_ringinfo))); \
+ SXG_RING_RETREAT_HEAD(_ringinfo); \
+ (_ringinfo)->Context[(_ringinfo)->Head] = NULL; \
}
-// For the given ring, return a pointer to the tail cmd and context,
-// clear the context and advance the tail
-#define SXG_RETURN_CMD(_ring, _ringinfo, _cmd, _context) { \
- (_cmd) = &(_ring)->Descriptors[(_ringinfo)->Tail]; \
+/*
+ * For the given ring, return a pointer to the tail cmd and context,
+ * clear the context and advance the tail
+ */
+#define SXG_RETURN_CMD(_ring, _ringinfo, _cmd, _context) { \
+ (_cmd) = &(_ring)->Descriptors[(_ringinfo)->Tail]; \
(_context) = (_ringinfo)->Context[(_ringinfo)->Tail]; \
- (_ringinfo)->Context[(_ringinfo)->Tail] = NULL; \
- SXG_RING_ADVANCE_TAIL(_ringinfo); \
+ (_ringinfo)->Context[(_ringinfo)->Tail] = NULL; \
+ SXG_RING_ADVANCE_TAIL(_ringinfo); \
}
-/***************************************************************************
- *
+/***************************************************************
* Host Command Buffer - commands to INIC via the Cmd Rings
*
- ***************************************************************************/
-/*
* 31 15 0
* .___________________.___________________.
* |<-------------- Sgl Low -------------->|
@@ -479,42 +506,43 @@ struct SXG_RING_INFO {
* |_________|_________|_________|_________|24 0x18
* |<----- LCnt ------>|<----- Flags ----->|
* |_________|_________|_________|_________|28 0x1c
- */
+ ****************************************************************/
#pragma pack(push, 1)
-struct SXG_CMD {
- dma_addr_t Sgl; // Physical address of SGL
+struct sxg_cmd {
+ dma_addr_t Sgl; /* Physical address of SGL */
union {
struct {
- dma64_addr_t FirstSgeAddress; // Address of first SGE
- u32 FirstSgeLength; // Length of first SGE
+ dma64_addr_t FirstSgeAddress; /* Address of first SGE */
+ u32 FirstSgeLength; /* Length of first SGE */
union {
- u32 Rsvd1; // TOE NA
- u32 SgeOffset; // Slowpath - 2nd SGE offset
- u32 Resid; // MDL completion - clobbers update
+ u32 Rsvd1; /* TOE NA */
+ u32 SgeOffset; /* Slowpath - 2nd SGE offset */
+ /* MDL completion - clobbers update */
+ u32 Resid;
};
union {
- u32 TotalLength; // Total transfer length
- u32 Mss; // LSO MSS
+ u32 TotalLength; /* Total transfer length */
+ u32 Mss; /* LSO MSS */
};
} Buffer;
};
union {
struct {
- unsigned char Flags:4; // slowpath flags
- unsigned char IpHl:4; // Ip header length (>>2)
- unsigned char MacLen; // Mac header len
+ unsigned char Flags:4; /* slowpath flags */
+ unsigned char IpHl:4; /* Ip header length (>>2) */
+ unsigned char MacLen; /* Mac header len */
} CsumFlags;
struct {
- ushort Flags:4; // slowpath flags
- ushort TcpHdrOff:7; // TCP
- ushort MacLen:5; // Mac header len
+ ushort Flags:4; /* slowpath flags */
+ ushort TcpHdrOff:7; /* TCP */
+ ushort MacLen:5; /* Mac header len */
} LsoFlags;
- ushort Flags; // flags
+ ushort Flags; /* flags */
};
union {
- ushort SgEntries; // SG entry count including first sge
+ ushort SgEntries; /* SG entry count including first sge */
struct {
- unsigned char Status; // Copied from event status
+ unsigned char Status; /* Copied from event status */
unsigned char NotUsed;
} Status;
};
@@ -522,13 +550,13 @@ struct SXG_CMD {
#pragma pack(pop)
#pragma pack(push, 1)
-struct VLAN_HDR {
+struct vlan_hdr {
ushort VlanTci;
ushort VlanTpid;
};
#pragma pack(pop)
-/*
+/********************************************************************
* Slowpath Flags:
*
*
@@ -558,36 +586,36 @@ struct VLAN_HDR {
* | LCnt |MAC hlen |Hlen|Flgs|
* |___________________|____|____|____|____|
*
- */
-// Slowpath CMD flags
-#define SXG_SLOWCMD_CSUM_IP 0x01 // Checksum IP
-#define SXG_SLOWCMD_CSUM_TCP 0x02 // Checksum TCP
-#define SXG_SLOWCMD_LSO 0x04 // Large segment send
-
-struct SXG_XMT_RING {
- struct SXG_CMD Descriptors[SXG_XMT_RING_SIZE];
+ *****************************************************************/
+/* Slowpath CMD flags */
+#define SXG_SLOWCMD_CSUM_IP 0x01 /* Checksum IP */
+#define SXG_SLOWCMD_CSUM_TCP 0x02 /* Checksum TCP */
+#define SXG_SLOWCMD_LSO 0x04 /* Large segment send */
+
+struct sxg_xmt_ring {
+ struct sxg_cmd Descriptors[SXG_XMT_RING_SIZE];
};
-struct SXG_RCV_RING {
- struct SXG_CMD Descriptors[SXG_RCV_RING_SIZE];
+struct sxg_rcv_ring {
+ struct sxg_cmd Descriptors[SXG_RCV_RING_SIZE];
};
-/***************************************************************************
+/*
* Share memory buffer types - Used to identify asynchronous
* shared memory allocation
- ***************************************************************************/
-enum SXG_BUFFER_TYPE {
- SXG_BUFFER_TYPE_RCV, // Receive buffer
- SXG_BUFFER_TYPE_SGL // SGL buffer
+ */
+enum sxg_buffer_type {
+ SXG_BUFFER_TYPE_RCV, /* Receive buffer */
+ SXG_BUFFER_TYPE_SGL /* SGL buffer */
};
-// State for SXG buffers
+/* State for SXG buffers */
#define SXG_BUFFER_FREE 0x01
#define SXG_BUFFER_BUSY 0x02
#define SXG_BUFFER_ONCARD 0x04
#define SXG_BUFFER_UPSTREAM 0x08
-/***************************************************************************
+/*
* Receive data buffers
*
* Receive data buffers are given to the Sahara card 128 at a time.
@@ -597,262 +625,363 @@ enum SXG_BUFFER_TYPE {
* DMA data into, and a virtual address, which is given back
* to the host in the "HostHandle" portion of an event.
* The receive descriptor data structure is defined below
- * as SXG_RCV_DATA_DESCRIPTOR, and the corresponding block
- * is defined as SXG_RCV_DESCRIPTOR_BLOCK.
+ * as sxg_rcv_data_descriptor, and the corresponding block
+ * is defined as sxg_rcv_descriptor_block.
*
* This receive descriptor block is given to the card by filling
- * in the Sgl field of a SXG_CMD entry from pAdapt->RcvRings[0]
+ * in the Sgl field of a sxg_cmd entry from pAdapt->RcvRings[0]
* with the physical address of the receive descriptor block.
*
* Both the receive buffers and the receive descriptor blocks
* require additional data structures to maintain them
* on a free queue and contain other information associated with them.
- * Those data structures are defined as the SXG_RCV_DATA_BUFFER_HDR
- * and SXG_RCV_DESCRIPTOR_BLOCK_HDR respectively.
+ * Those data structures are defined as the sxg_rcv_data_buffer_hdr
+ * and sxg_rcv_descriptor_block_hdr respectively.
*
* Since both the receive buffers and the receive descriptor block
* must be accessible by the card, both must be allocated out of
* shared memory. To ensure that we always have a descriptor
* block available for every 128 buffers, we allocate all of
* these resources together in a single block. This entire
- * block is managed by a SXG_RCV_BLOCK_HDR, who's sole purpose
+ * block is managed by a struct sxg_rcv_block_hdr, who's sole purpose
* is to maintain address information so that the entire block
* can be free later.
*
* Further complicating matters is the fact that the receive
* buffers must be variable in length in order to accomodate
* jumbo frame configurations. We configure the buffer
- * length so that the buffer and it's corresponding SXG_RCV_DATA_BUFFER_HDR
- * structure add up to an even boundary. Then we place the
- * remaining data structures after 128 of them as shown in
- * the following diagram:
+ * length so that the buffer and it's corresponding struct
+ * sxg_rcv_data_buffer_hdr structure add up to an even
+ * boundary. Then we place the remaining data structures after 128
+ * of them as shown in the following diagram:
*
* _________________________________________
* | |
* | Variable length receive buffer #1 |
* |_________________________________________|
* | |
- * | SXG_RCV_DATA_BUFFER_HDR #1 |
+ * | sxg_rcv_data_buffer_hdr #1 |
* |_________________________________________| <== Even 2k or 10k boundary
* | |
* | ... repeat 2-128 .. |
* |_________________________________________|
* | |
- * | SXG_RCV_DESCRIPTOR_BLOCK |
- * | Contains SXG_RCV_DATA_DESCRIPTOR * 128 |
+ * | struct sxg_rcv_descriptor_block |
+ * | Contains sxg_rcv_data_descriptor * 128 |
* |_________________________________________|
* | |
- * | SXG_RCV_DESCRIPTOR_BLOCK_HDR |
+ * | struct sxg_rcv_descriptor_block_hdr |
* |_________________________________________|
* | |
- * | SXG_RCV_BLOCK_HDR |
+ * | struct sxg_rcv_block_hdr |
* |_________________________________________|
*
* Memory consumption:
* Non-jumbo:
- * Buffers and SXG_RCV_DATA_BUFFER_HDR = 2k * 128 = 256k
- * + SXG_RCV_DESCRIPTOR_BLOCK = 2k
- * + SXG_RCV_DESCRIPTOR_BLOCK_HDR = ~32
- * + SXG_RCV_BLOCK_HDR = ~32
+ * Buffers and sxg_rcv_data_buffer_hdr = 2k * 128 = 256k
+ * + struct sxg_rcv_descriptor_block = 2k
+ * + struct sxg_rcv_descriptor_block_hdr = ~32
+ * + struct sxg_rcv_block_hdr = ~32
* => Total = ~258k/block
*
* Jumbo:
- * Buffers and SXG_RCV_DATA_BUFFER_HDR = 10k * 128 = 1280k
- * + SXG_RCV_DESCRIPTOR_BLOCK = 2k
- * + SXG_RCV_DESCRIPTOR_BLOCK_HDR = ~32
- * + SXG_RCV_BLOCK_HDR = ~32
+ * Buffers and sxg_rcv_data_buffer_hdr = 10k * 128 = 1280k
+ * + struct sxg_rcv_descriptor_block = 2k
+ * + struct sxg_rcv_descriptor_block_hdr = ~32
+ * + struct sxg_rcv_block_hdr = ~32
* => Total = ~1282k/block
*
- ***************************************************************************/
-#define SXG_RCV_DATA_BUFFERS 4096 // Amount to give to the card
-#define SXG_INITIAL_RCV_DATA_BUFFERS 8192 // Initial pool of buffers
-#define SXG_MIN_RCV_DATA_BUFFERS 2048 // Minimum amount and when to get more
-#define SXG_MAX_RCV_BLOCKS 128 // = 16384 receive buffers
-
-// Receive buffer header
-struct SXG_RCV_DATA_BUFFER_HDR {
- dma_addr_t PhysicalAddress; // Buffer physical address
- // Note - DO NOT USE the VirtualAddress field to locate data.
- // Use the sxg.h:SXG_RECEIVE_DATA_LOCATION macro instead.
- void *VirtualAddress; // Start of buffer
- struct LIST_ENTRY FreeList; // Free queue of buffers
- struct SXG_RCV_DATA_BUFFER_HDR *Next; // Fastpath data buffer queue
- u32 Size; // Buffer size
- u32 ByteOffset; // See SXG_RESTORE_MDL_OFFSET
- unsigned char State; // See SXG_BUFFER state above
- unsigned char Status; // Event status (to log PUSH)
- struct sk_buff *skb; // Double mapped (nbl and pkt)
+ */
+#define SXG_RCV_DATA_BUFFERS 8192 /* Amount to give to the card */
+#define SXG_INITIAL_RCV_DATA_BUFFERS 16384 /* Initial pool of buffers */
+/* Minimum amount and when to get more */
+#define SXG_MIN_RCV_DATA_BUFFERS 4096
+#define SXG_MAX_RCV_BLOCKS 256 /* = 32k receive buffers */
+
+/* Receive buffer header */
+struct sxg_rcv_data_buffer_hdr {
+ dma_addr_t PhysicalAddress; /* Buffer physical address */
+ /*
+ * Note - DO NOT USE the VirtualAddress field to locate data.
+ * Use the sxg.h:SXG_RECEIVE_DATA_LOCATION macro instead.
+ */
+ struct list_entry FreeList; /* Free queue of buffers */
+ unsigned char State; /* See SXG_BUFFER state above */
+ struct sk_buff * skb; /* Double mapped (nbl and pkt)*/
};
-// SxgSlowReceive uses the PACKET (skb) contained
-// in the SXG_RCV_DATA_BUFFER_HDR when indicating dumb-nic data
+/*
+ * SxgSlowReceive uses the PACKET (skb) contained
+ * in the struct sxg_rcv_data_buffer_hdr when indicating dumb-nic data
+ */
#define SxgDumbRcvPacket skb
-#define SXG_RCV_DATA_HDR_SIZE 256 // Space for SXG_RCV_DATA_BUFFER_HDR
-#define SXG_RCV_DATA_BUFFER_SIZE 2048 // Non jumbo = 2k including HDR
-#define SXG_RCV_JUMBO_BUFFER_SIZE 10240 // jumbo = 10k including HDR
+/* Space for struct sxg_rcv_data_buffer_hdr */
+#define SXG_RCV_DATA_HDR_SIZE sizeof(struct sxg_rcv_data_buffer_hdr)
+/* Non jumbo = 2k including HDR */
+#define SXG_RCV_DATA_BUFFER_SIZE 2048
+/* jumbo = 10k including HDR */
+#define SXG_RCV_JUMBO_BUFFER_SIZE 10240
-// Receive data descriptor
-struct SXG_RCV_DATA_DESCRIPTOR {
+/* Receive data descriptor */
+struct sxg_rcv_data_descriptor {
union {
- struct sk_buff *VirtualAddress; // Host handle
- u64 ForceTo8Bytes; // Force x86 to 8-byte boundary
+ struct sk_buff *VirtualAddress; /* Host handle */
+ u64 ForceTo8Bytes; /*Force x86 to 8-byte boundary*/
};
dma_addr_t PhysicalAddress;
};
-// Receive descriptor block
+/* Receive descriptor block */
#define SXG_RCV_DESCRIPTORS_PER_BLOCK 128
-#define SXG_RCV_DESCRIPTOR_BLOCK_SIZE 2048 // For sanity check
+#define SXG_RCV_DESCRIPTOR_BLOCK_SIZE 2048 /* For sanity check */
-struct SXG_RCV_DESCRIPTOR_BLOCK {
- struct SXG_RCV_DATA_DESCRIPTOR Descriptors[SXG_RCV_DESCRIPTORS_PER_BLOCK];
+struct sxg_rcv_descriptor_block {
+ struct sxg_rcv_data_descriptor Descriptors[SXG_RCV_DESCRIPTORS_PER_BLOCK];
};
-// Receive descriptor block header
-struct SXG_RCV_DESCRIPTOR_BLOCK_HDR {
- void *VirtualAddress; // Start of 2k buffer
- dma_addr_t PhysicalAddress; // ..and it's physical address
- struct LIST_ENTRY FreeList; // Free queue of descriptor blocks
- unsigned char State; // See SXG_BUFFER state above
+/* Receive descriptor block header */
+struct sxg_rcv_descriptor_block_hdr {
+ void *VirtualAddress; /* start of 2k buffer */
+ dma_addr_t PhysicalAddress; /* ..and it's physical address */
+ struct list_entry FreeList;/* free queue of descriptor blocks */
+ unsigned char State; /* see sxg_buffer state above */
};
-// Receive block header
-struct SXG_RCV_BLOCK_HDR {
- void *VirtualAddress; // Start of virtual memory
- dma_addr_t PhysicalAddress; // ..and it's physical address
- struct LIST_ENTRY AllList; // Queue of all SXG_RCV_BLOCKS
+/* Receive block header */
+struct sxg_rcv_block_hdr {
+ void *VirtualAddress; /* Start of virtual memory */
+ dma_addr_t PhysicalAddress; /* ..and it's physical address*/
+ struct list_entry AllList; /* Queue of all SXG_RCV_BLOCKS*/
};
-// Macros to determine data structure offsets into receive block
-#define SXG_RCV_BLOCK_SIZE(_Buffersize) \
+/* Macros to determine data structure offsets into receive block */
+#define SXG_RCV_BLOCK_SIZE(_Buffersize) \
(((_Buffersize) * SXG_RCV_DESCRIPTORS_PER_BLOCK) + \
- (sizeof(struct SXG_RCV_DESCRIPTOR_BLOCK)) + \
- (sizeof(struct SXG_RCV_DESCRIPTOR_BLOCK_HDR)) + \
- (sizeof(struct SXG_RCV_BLOCK_HDR)))
+ (sizeof(struct sxg_rcv_descriptor_block)) + \
+ (sizeof(struct sxg_rcv_descriptor_block_hdr)) + \
+ (sizeof(struct sxg_rcv_block_hdr)))
#define SXG_RCV_BUFFER_DATA_SIZE(_Buffersize) \
((_Buffersize) - SXG_RCV_DATA_HDR_SIZE)
#define SXG_RCV_DATA_BUFFER_HDR_OFFSET(_Buffersize) \
((_Buffersize) - SXG_RCV_DATA_HDR_SIZE)
-#define SXG_RCV_DESCRIPTOR_BLOCK_OFFSET(_Buffersize) \
+#define SXG_RCV_DESCRIPTOR_BLOCK_OFFSET(_Buffersize) \
((_Buffersize) * SXG_RCV_DESCRIPTORS_PER_BLOCK)
-#define SXG_RCV_DESCRIPTOR_BLOCK_HDR_OFFSET(_Buffersize) \
+#define SXG_RCV_DESCRIPTOR_BLOCK_HDR_OFFSET(_Buffersize) \
(((_Buffersize) * SXG_RCV_DESCRIPTORS_PER_BLOCK) + \
- (sizeof(struct SXG_RCV_DESCRIPTOR_BLOCK)))
+ (sizeof(struct sxg_rcv_descriptor_block)))
#define SXG_RCV_BLOCK_HDR_OFFSET(_Buffersize) \
(((_Buffersize) * SXG_RCV_DESCRIPTORS_PER_BLOCK) + \
- (sizeof(struct SXG_RCV_DESCRIPTOR_BLOCK)) + \
- (sizeof(struct SXG_RCV_DESCRIPTOR_BLOCK_HDR)))
-
-// Use the miniport reserved portion of the NBL to locate
-// our SXG_RCV_DATA_BUFFER_HDR structure.
-struct SXG_RCV_NBL_RESERVED {
- struct SXG_RCV_DATA_BUFFER_HDR *RcvDataBufferHdr;
- void *Available;
-};
+ (sizeof(struct sxg_rcv_descriptor_block)) + \
+ (sizeof(struct sxg_rcv_descriptor_block_hdr)))
-#define SXG_RCV_NBL_BUFFER_HDR(_NBL) (((PSXG_RCV_NBL_RESERVED)NET_BUFFER_LIST_MINIPORT_RESERVED(_NBL))->RcvDataBufferHdr)
+/* Scatter gather list buffer */
+#define SXG_INITIAL_SGL_BUFFERS 8192 /* Initial pool of SGL buffers */
+#define SXG_MIN_SGL_BUFFERS 2048 /* Minimum amount and when to get more*/
+/* Maximum to allocate (note ADAPT:ushort) */
+#define SXG_MAX_SGL_BUFFERS 16384
-/***************************************************************************
- * Scatter gather list buffer
- ***************************************************************************/
-#define SXG_INITIAL_SGL_BUFFERS 8192 // Initial pool of SGL buffers
-#define SXG_MIN_SGL_BUFFERS 2048 // Minimum amount and when to get more
-#define SXG_MAX_SGL_BUFFERS 16384 // Maximum to allocate (note ADAPT:ushort)
+/*
+ * SXG_SGL_POOL_PROPERTIES - This structure is used to define a pool of SGL
+ * buffers. These buffers are allocated out of shared memory and used to
+ * contain a physical scatter gather list structure that is shared
+ * with the card.
+ *
+ * We split our SGL buffers into multiple pools based on size. The motivation
+ * is that some applications perform very large I/Os (1MB for example), so
+ * we need to be able to allocate an SGL to accommodate such a request.
+ * But such an SGL would require 256 24-byte SG entries - ~6k.
+ * Given that the vast majority of I/Os are much smaller than 1M, allocating
+ * a single pool of SGL buffers would be a horribly inefficient use of
+ * memory.
+ *
+ * The following structure includes two fields relating to its size.
+ * The NBSize field specifies the largest NET_BUFFER that can be handled
+ * by the particular pool. The SGEntries field defines the size, in
+ * entries, of the SGL for that pool. The SGEntries is determined by
+ * dividing the NBSize by the expected page size (4k), and then padding
+ * it by some appropriate amount as insurance (20% or so..??).
+ */
+struct sxg_sgl_pool_properties {
+ u32 NBSize; /* Largest NET_BUFFER size for this pool */
+ ushort SGEntries; /* Number of entries in SGL */
+ ushort InitialBuffers; /* Number to allocate at initializationtime */
+ ushort MinBuffers; /* When to get more */
+ ushort MaxBuffers; /* When to stop */
+ ushort PerCpuThreshold;/* See sxgh.h:SXG_RESOURCES */
+};
-// Self identifying structure type
-enum SXG_SGL_TYPE {
- SXG_SGL_DUMB, // Dumb NIC SGL
- SXG_SGL_SLOW, // Slowpath protocol header - see below
- SXG_SGL_CHIMNEY // Chimney offload SGL
+/*
+ * At the moment I'm going to statically initialize 4 pools:
+ * 100k buffer pool: The vast majority of the expected buffers are expected
+ * to be less than or equal to 100k. At 30 entries per and
+ * 8k initial buffers amounts to ~4MB of memory
+ * NOTE - This used to be 64K with 20 entries, but during
+ * WHQL NDIS 6.0 Testing (2c_mini6stress) MS does their
+ * best to send absurd NBL's with ridiculous SGLs, we
+ * have received 400byte sends contained in SGL's that
+ * have 28 entries
+ * 1M buffer pool: Buffers between 64k and 1M. Allocate 256 initial
+ * buffers with 300 entries each => ~2MB of memory
+ * 5M buffer pool: Not expected often, if at all. 32 initial buffers
+ * at 1500 entries each => ~1MB of memory
+ * 10M buffer pool: Not expected at all, except under pathelogical conditions.
+ * Allocate one at initialization time.
+ * Note - 10M is the current limit of what we can realistically
+ * support due to the sahara SGL bug described in the
+ * SAHARA SGL WORKAROUND below. We will likely adjust the
+ * number of pools and/or pool properties over time.
+ */
+#define SXG_NUM_SGL_POOLS 4
+#define INITIALIZE_SGL_POOL_PROPERTIES \
+struct sxg_sgl_pool_properties SxgSglPoolProperties[SXG_NUM_SGL_POOLS] =\
+{ \
+ { 102400, 30, 8192, 2048, 16384, 256}, \
+ { 1048576, 300, 256, 128, 1024, 16}, \
+ { 5252880, 1500, 32, 16, 512, 0}, \
+ {10485760, 2700, 2, 4, 32, 0}, \
};
-// Note - the description below is Microsoft specific
-//
-// The following definition specifies the amount of shared memory to allocate
-// for the SCATTER_GATHER_LIST portion of the SXG_SCATTER_GATHER data structure.
-// The following considerations apply when setting this value:
-// - First, the Sahara card is designed to read the Microsoft SGL structure
-// straight out of host memory. This means that the SGL must reside in
-// shared memory. If the length here is smaller than the SGL for the
-// NET_BUFFER, then NDIS will allocate its own buffer. The buffer
-// that NDIS allocates is not in shared memory, so when this happens,
-// the SGL will need to be copied to a set of SXG_SCATTER_GATHER buffers.
-// In other words.. we don't want this value to be too small.
-// - On the other hand.. we're allocating up to 16k of these things. If
-// we make this too big, we start to consume a ton of memory..
-// At the moment, I'm going to limit the number of SG entries to 150.
-// If each entry maps roughly 4k, then this should cover roughly 600kB
-// NET_BUFFERs. Furthermore, since each entry is 24 bytes, the total
-// SGE portion of the structure consumes 3600 bytes, which should allow
-// the entire SXG_SCATTER_GATHER structure to reside comfortably within
-// a 4k block, providing the remaining fields stay under 500 bytes.
-//
-// So with 150 entries, the SXG_SCATTER_GATHER structure becomes roughly
-// 4k. At 16k of them, that amounts to 64M of shared memory. A ton, but
-// manageable.
-#define SXG_SGL_ENTRIES 150
-
-// The ucode expects an NDIS SGL structure that
-// is formatted for an x64 system. When running
-// on an x64 system, we can simply hand the NDIS SGL
-// to the card directly. For x86 systems we must reconstruct
-// the SGL. The following structure defines an x64
-// formatted SGL entry
-struct SXG_X64_SGE {
- dma64_addr_t Address; // same as wdm.h
- u32 Length; // same as wdm.h
- u32 CompilerPad; // The compiler pads to 8-bytes
- u64 Reserved; // u32 * in wdm.h. Force to 8 bytes
+extern struct sxg_sgl_pool_properties SxgSglPoolProperties[];
+
+#define SXG_MAX_SGL_BUFFER_SIZE \
+ SxgSglPoolProperties[SXG_NUM_SGL_POOLS - 1].NBSize
+
+/*
+ * SAHARA SGL WORKAROUND!!
+ * The current Sahara card uses a 16-bit counter when advancing
+ * SGL address locations. This means that if an SGL crosses
+ * a 64k boundary, the hardware will actually skip back to
+ * the start of the previous 64k boundary, with obviously
+ * undesirable results.
+ *
+ * We currently workaround this issue by allocating SGL buffers
+ * in 64k blocks and skipping over buffers that straddle the boundary.
+ */
+#define SXG_INVALID_SGL(_SxgSgl) \
+ (((_SxgSgl)->PhysicalAddress.LowPart & 0xFFFF0000) != \
+ (((_SxgSgl)->PhysicalAddress.LowPart + \
+ SXG_SGL_SIZE((_SxgSgl)->Pool)) & 0xFFFF0000))
+
+/*
+ * Allocate SGLs in blocks so we can skip over invalid entries.
+ * We allocation 64k worth of SGL buffers, including the
+ * struct sxg_sgl_block_hdr, plus one for padding
+ */
+#define SXG_SGL_BLOCK_SIZE 65536
+#define SXG_SGL_ALLOCATION_SIZE(_Pool) \
+ SXG_SGL_BLOCK_SIZE + SXG_SGL_SIZE(_Pool)
+
+struct sxg_sgl_block_hdr {
+ ushort Pool; /* Associated SGL pool */
+ /* struct sxg_scatter_gather blocks */
+ struct list_entry List;
+ dma64_addr_t PhysicalAddress;/* physical address */
};
-struct SCATTER_GATHER_ELEMENT {
- dma64_addr_t Address; // same as wdm.h
- u32 Length; // same as wdm.h
- u32 CompilerPad; // The compiler pads to 8-bytes
- u64 Reserved; // u32 * in wdm.h. Force to 8 bytes
+/*
+ * The following definition denotes the maximum block of memory that the
+ * card can DMA to.It is specified in the call to NdisMRegisterScatterGatherDma.
+ * For now, use the same value as used in the Slic/Oasis driver, which
+ * is 128M. That should cover any expected MDL that I can think of.
+ */
+#define SXG_MAX_PHYS_MAP (1024 * 1024 * 128)
+
+/* Self identifying structure type */
+enum SXG_SGL_TYPE {
+ SXG_SGL_DUMB, /* Dumb NIC SGL */
+ SXG_SGL_SLOW, /* Slowpath protocol header - see below */
+ SXG_SGL_CHIMNEY /* Chimney offload SGL */
};
-struct SCATTER_GATHER_LIST {
- u32 NumberOfElements;
- u32 *Reserved;
- struct SCATTER_GATHER_ELEMENT Elements[];
+/*
+ * The ucode expects an NDIS SGL structure that
+ * is formatted for an x64 system. When running
+ * on an x64 system, we can simply hand the NDIS SGL
+ * to the card directly. For x86 systems we must reconstruct
+ * the SGL. The following structure defines an x64
+ * formatted SGL entry
+ */
+struct sxg_x64_sge {
+ dma64_addr_t Address; /* same as wdm.h */
+ u32 Length; /* same as wdm.h */
+ u32 CompilerPad; /* The compiler pads to 8-bytes */
+ u64 Reserved; /* u32 * in wdm.h. Force to 8 bytes */
};
-// The card doesn't care about anything except elements, so
-// we can leave the u32 * reserved field alone in the following
-// SGL structure. But redefine from wdm.h:SCATTER_GATHER_LIST so
-// we can specify SXG_X64_SGE and define a fixed number of elements
-struct SXG_X64_SGL {
+/*
+ * Our SGL structure - Essentially the same as
+ * wdm.h:SCATTER_GATHER_LIST. Note the variable number of
+ * elements based on the pool specified above
+ */
+struct sxg_x64_sgl {
u32 NumberOfElements;
u32 *Reserved;
- struct SXG_X64_SGE Elements[SXG_SGL_ENTRIES];
+ struct sxg_x64_sge Elements[1]; /* Variable */
};
-struct SXG_SCATTER_GATHER {
- enum SXG_SGL_TYPE Type; // FIRST! Dumb-nic or offload
- void *adapter; // Back pointer to adapter
- struct LIST_ENTRY FreeList; // Free SXG_SCATTER_GATHER blocks
- struct LIST_ENTRY AllList; // All SXG_SCATTER_GATHER blocks
- dma_addr_t PhysicalAddress; // physical address
- unsigned char State; // See SXG_BUFFER state above
- unsigned char CmdIndex; // Command ring index
- struct sk_buff *DumbPacket; // Associated Packet
- u32 Direction; // For asynchronous completions
- u32 CurOffset; // Current SGL offset
- u32 SglRef; // SGL reference count
- struct VLAN_HDR VlanTag; // VLAN tag to be inserted into SGL
- struct SCATTER_GATHER_LIST *pSgl; // SGL Addr. Possibly &Sgl
- struct SXG_X64_SGL Sgl; // SGL handed to card
+struct sxg_scatter_gather {
+ enum SXG_SGL_TYPE Type; /* FIRST! Dumb-nic or offload */
+ ushort Pool; /* Associated SGL pool */
+ ushort Entries; /* SGL total entries */
+ void * adapter; /* Back pointer to adapter */
+ /* Free struct sxg_scatter_gather blocks */
+ struct list_entry FreeList;
+ /* All struct sxg_scatter_gather blocks */
+ struct list_entry AllList;
+ dma_addr_t PhysicalAddress;/* physical address */
+ unsigned char State; /* See SXG_BUFFER state above */
+ unsigned char CmdIndex; /* Command ring index */
+ struct sk_buff *DumbPacket; /* Associated Packet */
+ /* For asynchronous completions */
+ u32 Direction;
+ u32 CurOffset; /* Current SGL offset */
+ u32 SglRef; /* SGL reference count */
+ struct vlan_hdr VlanTag; /* VLAN tag to be inserted into SGL */
+ struct sxg_x64_sgl *pSgl; /* SGL Addr. Possibly &Sgl */
+ struct sxg_x64_sgl Sgl; /* SGL handed to card */
};
+/*
+ * Note - the "- 1" is because struct sxg_scatter_gather=>struct sxg_x64_sgl
+ * includes 1 SGE..
+ */
+#define SXG_SGL_SIZE(_Pool) \
+ (sizeof(struct sxg_scatter_gather) + \
+ ((SxgSglPoolProperties[_Pool].SGEntries - 1) * \
+ sizeof(struct sxg_x64_sge)))
+
+/* Force NDIS to give us it's own buffer so we can reformat to our own */
+#define SXG_SGL_BUFFER(_SxgSgl) NULL //VSS change this value and test
+#define SXG_SGL_BUFFER_LENGTH(_SxgSgl) 0 //VSS change this value and test
+#define SXG_SGL_BUF_SIZE 0 //VSS change this value and test
+
+/*
#if defined(CONFIG_X86_64)
-#define SXG_SGL_BUFFER(_SxgSgl) (&_SxgSgl->Sgl)
-#define SXG_SGL_BUF_SIZE sizeof(struct SXG_X64_SGL)
+#define SXG_SGL_BUFFER(_SxgSgl) (&_SxgSgl->Sgl)
+#define SXG_SGL_BUFFER_LENGTH(_SxgSgl) ((_SxgSgl)->Entries * \
+ sizeof(struct sxg_x64_sge))
+#define SXG_SGL_BUF_SIZE sizeof(struct sxg_x64_sgl)
#elif defined(CONFIG_X86)
// Force NDIS to give us it's own buffer so we can reformat to our own
-#define SXG_SGL_BUFFER(_SxgSgl) NULL
+#define SXG_SGL_BUFFER(_SxgSgl) NULL
+#define SXG_SGL_BUFFER_LENGTH(_SxgSgl) 0
#define SXG_SGL_BUF_SIZE 0
#else
#error staging: sxg: driver is for X86 only!
#endif
+*/
+/* Microcode statistics */
+struct sxg_ucode_stats {
+ u32 RPDQOflow; /* PDQ overflow (unframed ie dq & drop 1st) */
+ u32 XDrops; /* Xmt drops due to no xmt buffer */
+ u32 ERDrops; /* Rcv drops due to ER full */
+ u32 NBDrops; /* Rcv drops due to out of host buffers */
+ u32 PQDrops; /* Rcv drops due to PDQ full */
+ /* Rcv drops due to bad frame: no link addr match, frlen > max */
+ u32 BFDrops;
+ u32 UPDrops; /* Rcv drops due to UPFq full */
+ u32 XNoBufs; /* Xmt drop due to no DRAM Xmit buffer or PxyBuf */
+};
+
+
diff --git a/drivers/staging/sxg/sxghw.h b/drivers/staging/sxg/sxghw.h
index b0efff9ff117..efcbd453e160 100644
--- a/drivers/staging/sxg/sxghw.h
+++ b/drivers/staging/sxg/sxghw.h
@@ -1,4 +1,4 @@
-/*
+/*************************************************************
* Copyright © 1997-2007 Alacritech, Inc. All rights reserved
*
* $Id: sxghw.h,v 1.2 2008/07/24 17:24:23 chris Exp $
@@ -7,682 +7,873 @@
*
* This file contains structures and definitions for the
* Alacritech Sahara hardware
- */
+ *
+ **********************************************************/
-/*******************************************************************************
- * Configuration space
- *******************************************************************************/
+/* PCI Configuration space */
/* PCI Vendor ID */
#define SXG_VENDOR_ID 0x139A /* Alacritech's Vendor ID */
-// PCI Device ID
+/* PCI Device ID */
#define SXG_DEVICE_ID 0x0009 /* Sahara Device ID */
-//
-// Subsystem IDs.
-//
-// The subsystem ID value is broken into bit fields as follows:
-// Bits [15:12] - Function
-// Bits [11:8] - OEM and/or operating system.
-// Bits [7:0] - Base SID.
-//
-// SSID field (bit) masks
-#define SSID_BASE_MASK 0x00FF // Base subsystem ID mask
-#define SSID_OEM_MASK 0x0F00 // Subsystem OEM mask
-#define SSID_FUNC_MASK 0xF000 // Subsystem function mask
-
-// Base SSID's
-#define SSID_SAHARA_PROTO 0x0018 // 100022 Sahara prototype (XenPak) board
-#define SSID_SAHARA_FIBER 0x0019 // 100023 Sahara 1-port fiber board
-#define SSID_SAHARA_COPPER 0x001A // 100024 Sahara 1-port copper board
-
-// Useful SSID macros
-#define SSID_BASE(ssid) ((ssid) & SSID_BASE_MASK) // isolate base SSID bits
-#define SSID_OEM(ssid) ((ssid) & SSID_OEM_MASK) // isolate SSID OEM bits
-#define SSID_FUNC(ssid) ((ssid) & SSID_FUNC_MASK) // isolate SSID function bits
-
-/*******************************************************************************
- * HW Register Space
- *******************************************************************************/
-#define SXG_HWREG_MEMSIZE 0x4000 // 16k
+/*
+ * Subsystem IDs.
+ *
+ * The subsystem ID value is broken into bit fields as follows:
+ * Bits [15:12] - Function
+ * Bits [11:8] - OEM and/or operating system.
+ * Bits [7:0] - Base SID.
+ */
+
+/* SSID field (bit) masks */
+#define SSID_BASE_MASK 0x00FF /* Base subsystem ID mask */
+#define SSID_OEM_MASK 0x0F00 /* Subsystem OEM mask */
+#define SSID_FUNC_MASK 0xF000 /* Subsystem function mask */
+
+/* Base SSID's */
+/* 100022 Sahara prototype (XenPak) board */
+#define SSID_SAHARA_PROTO 0x0018
+#define SSID_SAHARA_FIBER 0x0019 /* 100023 Sahara 1-port fiber board */
+#define SSID_SAHARA_COPPER 0x001A /* 100024 Sahara 1-port copper board */
+
+/* Useful SSID macros */
+/* isolate base SSID bits */
+#define SSID_BASE(ssid) ((ssid) & SSID_BASE_MASK)
+/* isolate SSID OEM bits */
+#define SSID_OEM(ssid) ((ssid) & SSID_OEM_MASK)
+/* isolate SSID function bits */
+#define SSID_FUNC(ssid) ((ssid) & SSID_FUNC_MASK)
+
+
+/* HW Register Space */
+#define SXG_HWREG_MEMSIZE 0x4000 /* 16k */
#pragma pack(push, 1)
-struct SXG_HW_REGS {
- u32 Reset; // Write 0xdead to invoke soft reset
- u32 Pad1; // No register defined at offset 4
- u32 InterruptMask0; // Deassert legacy interrupt on function 0
- u32 InterruptMask1; // Deassert legacy interrupt on function 1
- u32 UcodeDataLow; // Store microcode instruction bits 31-0
- u32 UcodeDataMiddle; // Store microcode instruction bits 63-32
- u32 UcodeDataHigh; // Store microcode instruction bits 95-64
- u32 UcodeAddr; // Store microcode address - See flags below
- u32 PadTo0x80[24]; // Pad to Xcv configuration registers
- u32 MacConfig0; // 0x80 - AXGMAC Configuration Register 0
- u32 MacConfig1; // 0x84 - AXGMAC Configuration Register 1
- u32 MacConfig2; // 0x88 - AXGMAC Configuration Register 2
- u32 MacConfig3; // 0x8C - AXGMAC Configuration Register 3
- u32 MacAddressLow; // 0x90 - AXGMAC MAC Station Address - octets 1-4
- u32 MacAddressHigh; // 0x94 - AXGMAC MAC Station Address - octets 5-6
- u32 MacReserved1[2]; // 0x98 - AXGMAC Reserved
- u32 MacMaxFrameLen; // 0xA0 - AXGMAC Maximum Frame Length
- u32 MacReserved2[2]; // 0xA4 - AXGMAC Reserved
- u32 MacRevision; // 0xAC - AXGMAC Revision Level Register
- u32 MacReserved3[4]; // 0xB0 - AXGMAC Reserved
- u32 MacAmiimCmd; // 0xC0 - AXGMAC AMIIM Command Register
- u32 MacAmiimField; // 0xC4 - AXGMAC AMIIM Field Register
- u32 MacAmiimConfig; // 0xC8 - AXGMAC AMIIM Configuration Register
- u32 MacAmiimLink; // 0xCC - AXGMAC AMIIM Link Fail Vector Register
- u32 MacAmiimIndicator; // 0xD0 - AXGMAC AMIIM Indicator Registor
- u32 PadTo0x100[11]; // 0xD4 - 0x100 - Pad
- u32 XmtConfig; // 0x100 - Transmit Configuration Register
- u32 RcvConfig; // 0x104 - Receive Configuration Register 1
- u32 LinkAddress0Low; // 0x108 - Link address 0
- u32 LinkAddress0High; // 0x10C - Link address 0
- u32 LinkAddress1Low; // 0x110 - Link address 1
- u32 LinkAddress1High; // 0x114 - Link address 1
- u32 LinkAddress2Low; // 0x118 - Link address 2
- u32 LinkAddress2High; // 0x11C - Link address 2
- u32 LinkAddress3Low; // 0x120 - Link address 3
- u32 LinkAddress3High; // 0x124 - Link address 3
- u32 ToeplitzKey[10]; // 0x128 - 0x150 - Toeplitz key
- u32 SocketKey[10]; // 0x150 - 0x178 - Socket Key
- u32 LinkStatus; // 0x178 - Link status
- u32 ClearStats; // 0x17C - Clear Stats
- u32 XmtErrorsLow; // 0x180 - Transmit stats - errors
- u32 XmtErrorsHigh; // 0x184 - Transmit stats - errors
- u32 XmtFramesLow; // 0x188 - Transmit stats - frame count
- u32 XmtFramesHigh; // 0x18C - Transmit stats - frame count
- u32 XmtBytesLow; // 0x190 - Transmit stats - byte count
- u32 XmtBytesHigh; // 0x194 - Transmit stats - byte count
- u32 XmtTcpSegmentsLow; // 0x198 - Transmit stats - TCP segments
- u32 XmtTcpSegmentsHigh; // 0x19C - Transmit stats - TCP segments
- u32 XmtTcpBytesLow; // 0x1A0 - Transmit stats - TCP bytes
- u32 XmtTcpBytesHigh; // 0x1A4 - Transmit stats - TCP bytes
- u32 RcvErrorsLow; // 0x1A8 - Receive stats - errors
- u32 RcvErrorsHigh; // 0x1AC - Receive stats - errors
- u32 RcvFramesLow; // 0x1B0 - Receive stats - frame count
- u32 RcvFramesHigh; // 0x1B4 - Receive stats - frame count
- u32 RcvBytesLow; // 0x1B8 - Receive stats - byte count
- u32 RcvBytesHigh; // 0x1BC - Receive stats - byte count
- u32 RcvTcpSegmentsLow; // 0x1C0 - Receive stats - TCP segments
- u32 RcvTcpSegmentsHigh; // 0x1C4 - Receive stats - TCP segments
- u32 RcvTcpBytesLow; // 0x1C8 - Receive stats - TCP bytes
- u32 RcvTcpBytesHigh; // 0x1CC - Receive stats - TCP bytes
- u32 PadTo0x200[12]; // 0x1D0 - 0x200 - Pad
- u32 Software[1920]; // 0x200 - 0x2000 - Software defined (not used)
- u32 MsixTable[1024]; // 0x2000 - 0x3000 - MSIX Table
- u32 MsixBitArray[1024]; // 0x3000 - 0x4000 - MSIX Pending Bit Array
+struct sxg_hw_regs {
+ u32 Reset; /* Write 0xdead to invoke soft reset */
+ u32 Pad1; /* No register defined at offset 4 */
+ u32 InterruptMask0; /* Deassert legacy interrupt on function 0 */
+ u32 InterruptMask1; /* Deassert legacy interrupt on function 1 */
+ u32 UcodeDataLow; /* Store microcode instruction bits 31-0 */
+ u32 UcodeDataMiddle; /* Store microcode instruction bits 63-32 */
+ u32 UcodeDataHigh; /* Store microcode instruction bits 95-64 */
+ u32 UcodeAddr; /* Store microcode address - See flags below */
+ u32 PadTo0x80[24]; /* Pad to Xcv configuration registers */
+ u32 MacConfig0; /* 0x80 - AXGMAC Configuration Register 0 */
+ u32 MacConfig1; /* 0x84 - AXGMAC Configuration Register 1 */
+ u32 MacConfig2; /* 0x88 - AXGMAC Configuration Register 2 */
+ u32 MacConfig3; /* 0x8C - AXGMAC Configuration Register 3 */
+ u32 MacAddressLow; /* 0x90 - AXGMAC MAC Station Address - octets 1-4 */
+ u32 MacAddressHigh; /* 0x94 - AXGMAC MAC Station Address - octets 5-6 */
+ u32 MacReserved1[2]; /* 0x98 - AXGMAC Reserved */
+ u32 MacMaxFrameLen; /* 0xA0 - AXGMAC Maximum Frame Length */
+ u32 MacReserved2[2]; /* 0xA4 - AXGMAC Reserved */
+ u32 MacRevision; /* 0xAC - AXGMAC Revision Level Register */
+ u32 MacReserved3[4]; /* 0xB0 - AXGMAC Reserved */
+ u32 MacAmiimCmd; /* 0xC0 - AXGMAC AMIIM Command Register */
+ u32 MacAmiimField; /* 0xC4 - AXGMAC AMIIM Field Register */
+ u32 MacAmiimConfig; /* 0xC8 - AXGMAC AMIIM Configuration Register */
+ u32 MacAmiimLink; /* 0xCC - AXGMAC AMIIM Link Fail Vector Register */
+ u32 MacAmiimIndicator; /* 0xD0 - AXGMAC AMIIM Indicator Registor */
+ u32 PadTo0x100[11]; /* 0xD4 - 0x100 - Pad */
+ u32 XmtConfig; /* 0x100 - Transmit Configuration Register */
+ u32 RcvConfig; /* 0x104 - Receive Configuration Register 1 */
+ u32 LinkAddress0Low; /* 0x108 - Link address 0 */
+ u32 LinkAddress0High; /* 0x10C - Link address 0 */
+ u32 LinkAddress1Low; /* 0x110 - Link address 1 */
+ u32 LinkAddress1High; /* 0x114 - Link address 1 */
+ u32 LinkAddress2Low; /* 0x118 - Link address 2 */
+ u32 LinkAddress2High; /* 0x11C - Link address 2 */
+ u32 LinkAddress3Low; /* 0x120 - Link address 3 */
+ u32 LinkAddress3High; /* 0x124 - Link address 3 */
+ u32 ToeplitzKey[10]; /* 0x128 - 0x150 - Toeplitz key */
+ u32 SocketKey[10]; /* 0x150 - 0x178 - Socket Key */
+ u32 LinkStatus; /* 0x178 - Link status */
+ u32 ClearStats; /* 0x17C - Clear Stats */
+ u32 XmtErrorsLow; /* 0x180 - Transmit stats - errors */
+ u32 XmtErrorsHigh; /* 0x184 - Transmit stats - errors */
+ u32 XmtFramesLow; /* 0x188 - Transmit stats - frame count */
+ u32 XmtFramesHigh; /* 0x18C - Transmit stats - frame count */
+ u32 XmtBytesLow; /* 0x190 - Transmit stats - byte count */
+ u32 XmtBytesHigh; /* 0x194 - Transmit stats - byte count */
+ u32 XmtTcpSegmentsLow; /* 0x198 - Transmit stats - TCP segments */
+ u32 XmtTcpSegmentsHigh; /* 0x19C - Transmit stats - TCP segments */
+ u32 XmtTcpBytesLow; /* 0x1A0 - Transmit stats - TCP bytes */
+ u32 XmtTcpBytesHigh; /* 0x1A4 - Transmit stats - TCP bytes */
+ u32 RcvErrorsLow; /* 0x1A8 - Receive stats - errors */
+ u32 RcvErrorsHigh; /* 0x1AC - Receive stats - errors */
+ u32 RcvFramesLow; /* 0x1B0 - Receive stats - frame count */
+ u32 RcvFramesHigh; /* 0x1B4 - Receive stats - frame count */
+ u32 RcvBytesLow; /* 0x1B8 - Receive stats - byte count */
+ u32 RcvBytesHigh; /* 0x1BC - Receive stats - byte count */
+ u32 RcvTcpSegmentsLow; /* 0x1C0 - Receive stats - TCP segments */
+ u32 RcvTcpSegmentsHigh; /* 0x1C4 - Receive stats - TCP segments */
+ u32 RcvTcpBytesLow; /* 0x1C8 - Receive stats - TCP bytes */
+ u32 RcvTcpBytesHigh; /* 0x1CC - Receive stats - TCP bytes */
+ u32 PadTo0x200[12]; /* 0x1D0 - 0x200 - Pad */
+ u32 Software[1920]; /* 0x200 - 0x2000 - Software defined (not used) */
+ u32 MsixTable[1024]; /* 0x2000 - 0x3000 - MSIX Table */
+ u32 MsixBitArray[1024]; /* 0x3000 - 0x4000 - MSIX Pending Bit Array */
};
#pragma pack(pop)
-// Microcode Address Flags
-#define MICROCODE_ADDRESS_GO 0x80000000 // Start microcode
-#define MICROCODE_ADDRESS_WRITE 0x40000000 // Store microcode
-#define MICROCODE_ADDRESS_READ 0x20000000 // Read microcode
-#define MICROCODE_ADDRESS_PARITY 0x10000000 // Parity error detected
-#define MICROCODE_ADDRESS_MASK 0x00001FFF // Address bits
+/* Microcode Address Flags */
+#define MICROCODE_ADDRESS_GO 0x80000000 /* Start microcode */
+#define MICROCODE_ADDRESS_WRITE 0x40000000 /* Store microcode */
+#define MICROCODE_ADDRESS_READ 0x20000000 /* Read microcode */
+#define MICROCODE_ADDRESS_PARITY 0x10000000/* Parity error detected */
+#define MICROCODE_ADDRESS_MASK 0x00001FFF /* Address bits */
-// Link Address Registers
-#define LINK_ADDRESS_ENABLE 0x80000000 // Applied to link address high
+/* Link Address Registers */
+/* Applied to link address high */
+#define LINK_ADDRESS_ENABLE 0x80000000
-// Microsoft register space size
-#define SXG_UCODEREG_MEMSIZE 0x40000 // 256k
+/* Microsoft register space size */
+#define SXG_UCODEREG_MEMSIZE 0x40000 /* 256k */
-// Sahara microcode register address format. The command code,
-// extended command code, and associated processor are encoded in
-// the address bits as follows
-#define SXG_ADDRESS_CODE_SHIFT 2 // Base command code
+/*
+ * Sahara microcode register address format. The command code,
+ * extended command code, and associated processor are encoded in
+ * the address bits as follows
+ */
+#define SXG_ADDRESS_CODE_SHIFT 2 /* Base command code */
#define SXG_ADDRESS_CODE_MASK 0x0000003C
-#define SXG_ADDRESS_EXCODE_SHIFT 6 // Extended (or sub) command code
+/* Extended (or sub) command code */
+#define SXG_ADDRESS_EXCODE_SHIFT 6
#define SXG_ADDRESS_EXCODE_MASK 0x00001FC0
-#define SXG_ADDRESS_CPUID_SHIFT 13 // CPU
+#define SXG_ADDRESS_CPUID_SHIFT 13 /* CPU */
#define SXG_ADDRESS_CPUID_MASK 0x0003E000
-#define SXG_REGISTER_SIZE_PER_CPU 0x00002000 // Used to sanity check UCODE_REGS structure
-
-// Sahara receive sequencer status values
-#define SXG_RCV_STATUS_ATTN 0x80000000 // Attention
-#define SXG_RCV_STATUS_TRANSPORT_MASK 0x3F000000 // Transport mask
-#define SXG_RCV_STATUS_TRANSPORT_ERROR 0x20000000 // Transport error
-#define SXG_RCV_STATUS_TRANSPORT_CSUM 0x23000000 // Transport cksum error
-#define SXG_RCV_STATUS_TRANSPORT_UFLOW 0x22000000 // Transport underflow
-#define SXG_RCV_STATUS_TRANSPORT_HDRLEN 0x20000000 // Transport header length
-#define SXG_RCV_STATUS_TRANSPORT_FLAGS 0x10000000 // Transport flags detected
-#define SXG_RCV_STATUS_TRANSPORT_OPTS 0x08000000 // Transport options detected
-#define SXG_RCV_STATUS_TRANSPORT_SESS_MASK 0x07000000 // Transport DDP
-#define SXG_RCV_STATUS_TRANSPORT_DDP 0x06000000 // Transport DDP
-#define SXG_RCV_STATUS_TRANSPORT_iSCSI 0x05000000 // Transport iSCSI
-#define SXG_RCV_STATUS_TRANSPORT_NFS 0x04000000 // Transport NFS
-#define SXG_RCV_STATUS_TRANSPORT_FTP 0x03000000 // Transport FTP
-#define SXG_RCV_STATUS_TRANSPORT_HTTP 0x02000000 // Transport HTTP
-#define SXG_RCV_STATUS_TRANSPORT_SMB 0x01000000 // Transport SMB
-#define SXG_RCV_STATUS_NETWORK_MASK 0x00FF0000 // Network mask
-#define SXG_RCV_STATUS_NETWORK_ERROR 0x00800000 // Network error
-#define SXG_RCV_STATUS_NETWORK_CSUM 0x00830000 // Network cksum error
-#define SXG_RCV_STATUS_NETWORK_UFLOW 0x00820000 // Network underflow error
-#define SXG_RCV_STATUS_NETWORK_HDRLEN 0x00800000 // Network header length
-#define SXG_RCV_STATUS_NETWORK_OFLOW 0x00400000 // Network overflow detected
-#define SXG_RCV_STATUS_NETWORK_MCAST 0x00200000 // Network multicast detected
-#define SXG_RCV_STATUS_NETWORK_OPTIONS 0x00100000 // Network options detected
-#define SXG_RCV_STATUS_NETWORK_OFFSET 0x00080000 // Network offset detected
-#define SXG_RCV_STATUS_NETWORK_FRAGMENT 0x00040000 // Network fragment detected
-#define SXG_RCV_STATUS_NETWORK_TRANS_MASK 0x00030000 // Network transport type mask
-#define SXG_RCV_STATUS_NETWORK_UDP 0x00020000 // UDP
-#define SXG_RCV_STATUS_NETWORK_TCP 0x00010000 // TCP
-#define SXG_RCV_STATUS_IPONLY 0x00008000 // IP-only not TCP
-#define SXG_RCV_STATUS_PKT_PRI 0x00006000 // Receive priority
-#define SXG_RCV_STATUS_PKT_PRI_SHFT 13 // Receive priority shift
-#define SXG_RCV_STATUS_PARITY 0x00001000 // MAC Receive RAM parity error
-#define SXG_RCV_STATUS_ADDRESS_MASK 0x00000F00 // Link address detection mask
-#define SXG_RCV_STATUS_ADDRESS_D 0x00000B00 // Link address D
-#define SXG_RCV_STATUS_ADDRESS_C 0x00000A00 // Link address C
-#define SXG_RCV_STATUS_ADDRESS_B 0x00000900 // Link address B
-#define SXG_RCV_STATUS_ADDRESS_A 0x00000800 // Link address A
-#define SXG_RCV_STATUS_ADDRESS_BCAST 0x00000300 // Link address broadcast
-#define SXG_RCV_STATUS_ADDRESS_MCAST 0x00000200 // Link address multicast
-#define SXG_RCV_STATUS_ADDRESS_CMCAST 0x00000100 // Link control multicast
-#define SXG_RCV_STATUS_LINK_MASK 0x000000FF // Link status mask
-#define SXG_RCV_STATUS_LINK_ERROR 0x00000080 // Link error
-#define SXG_RCV_STATUS_LINK_MASK 0x000000FF // Link status mask
-#define SXG_RCV_STATUS_LINK_PARITY 0x00000087 // RcvMacQ parity error
-#define SXG_RCV_STATUS_LINK_EARLY 0x00000086 // Data early
-#define SXG_RCV_STATUS_LINK_BUFOFLOW 0x00000085 // Buffer overflow
-#define SXG_RCV_STATUS_LINK_CODE 0x00000084 // Link code error
-#define SXG_RCV_STATUS_LINK_DRIBBLE 0x00000083 // Dribble nibble
-#define SXG_RCV_STATUS_LINK_CRC 0x00000082 // CRC error
-#define SXG_RCV_STATUS_LINK_OFLOW 0x00000081 // Link overflow
-#define SXG_RCV_STATUS_LINK_UFLOW 0x00000080 // Link underflow
-#define SXG_RCV_STATUS_LINK_8023 0x00000020 // 802.3
-#define SXG_RCV_STATUS_LINK_SNAP 0x00000010 // Snap
-#define SXG_RCV_STATUS_LINK_VLAN 0x00000008 // VLAN
-#define SXG_RCV_STATUS_LINK_TYPE_MASK 0x00000007 // Network type mask
-#define SXG_RCV_STATUS_LINK_CONTROL 0x00000003 // Control packet
-#define SXG_RCV_STATUS_LINK_IPV6 0x00000002 // IPv6 packet
-#define SXG_RCV_STATUS_LINK_IPV4 0x00000001 // IPv4 packet
-
-/***************************************************************************
- * Sahara receive and transmit configuration registers
- ***************************************************************************/
-#define RCV_CONFIG_RESET 0x80000000 // RcvConfig register reset
-#define RCV_CONFIG_ENABLE 0x40000000 // Enable the receive logic
-#define RCV_CONFIG_ENPARSE 0x20000000 // Enable the receive parser
-#define RCV_CONFIG_SOCKET 0x10000000 // Enable the socket detector
-#define RCV_CONFIG_RCVBAD 0x08000000 // Receive all bad frames
-#define RCV_CONFIG_CONTROL 0x04000000 // Receive all control frames
-#define RCV_CONFIG_RCVPAUSE 0x02000000 // Enable pause transmit when attn
-#define RCV_CONFIG_TZIPV6 0x01000000 // Include TCP port w/ IPv6 toeplitz
-#define RCV_CONFIG_TZIPV4 0x00800000 // Include TCP port w/ IPv4 toeplitz
-#define RCV_CONFIG_FLUSH 0x00400000 // Flush buffers
-#define RCV_CONFIG_PRIORITY_MASK 0x00300000 // Priority level
-#define RCV_CONFIG_HASH_MASK 0x00030000 // Hash depth
-#define RCV_CONFIG_HASH_8 0x00000000 // Hash depth 8
-#define RCV_CONFIG_HASH_16 0x00010000 // Hash depth 16
-#define RCV_CONFIG_HASH_4 0x00020000 // Hash depth 4
-#define RCV_CONFIG_HASH_2 0x00030000 // Hash depth 2
-#define RCV_CONFIG_BUFLEN_MASK 0x0000FFF0 // Buffer length bits 15:4. ie multiple of 16.
-#define RCV_CONFIG_SKT_DIS 0x00000008 // Disable socket detection on attn
-// Macro to determine RCV_CONFIG_BUFLEN based on maximum frame size.
-// We add 18 bytes for Sahara receive status and padding, plus 4 bytes for CRC,
-// and round up to nearest 16 byte boundary
-#define RCV_CONFIG_BUFSIZE(_MaxFrame) ((((_MaxFrame) + 22) + 15) & RCV_CONFIG_BUFLEN_MASK)
-
-#define XMT_CONFIG_RESET 0x80000000 // XmtConfig register reset
-#define XMT_CONFIG_ENABLE 0x40000000 // Enable transmit logic
-#define XMT_CONFIG_MAC_PARITY 0x20000000 // Inhibit MAC RAM parity error
-#define XMT_CONFIG_BUF_PARITY 0x10000000 // Inhibit D2F buffer parity error
-#define XMT_CONFIG_MEM_PARITY 0x08000000 // Inhibit 1T SRAM parity error
-#define XMT_CONFIG_INVERT_PARITY 0x04000000 // Invert MAC RAM parity
-#define XMT_CONFIG_INITIAL_IPID 0x0000FFFF // Initial IPID
-
-/***************************************************************************
- * A-XGMAC Registers - Occupy 0x80 - 0xD4 of the SXG_HW_REGS
+/* Used to sanity check UCODE_REGS structure */
+#define SXG_REGISTER_SIZE_PER_CPU 0x00002000
+
+/* Sahara receive sequencer status values */
+#define SXG_RCV_STATUS_ATTN 0x80000000 /* Attention */
+#define SXG_RCV_STATUS_TRANSPORT_MASK 0x3F000000 /* Transport mask */
+#define SXG_RCV_STATUS_TRANSPORT_ERROR 0x20000000 /* Transport error */
+/* Transport cksum error */
+#define SXG_RCV_STATUS_TRANSPORT_CSUM 0x23000000
+/* Transport underflow */
+#define SXG_RCV_STATUS_TRANSPORT_UFLOW 0x22000000
+ /* Transport header length */
+#define SXG_RCV_STATUS_TRANSPORT_HDRLEN 0x20000000
+/* Transport flags detected */
+#define SXG_RCV_STATUS_TRANSPORT_FLAGS 0x10000000
+ /* Transport options detected */
+#define SXG_RCV_STATUS_TRANSPORT_OPTS 0x08000000
+#define SXG_RCV_STATUS_TRANSPORT_SESS_MASK 0x07000000 /* Transport DDP */
+#define SXG_RCV_STATUS_TRANSPORT_DDP 0x06000000 /* Transport DDP */
+#define SXG_RCV_STATUS_TRANSPORT_iSCSI 0x05000000 /* Transport iSCSI */
+#define SXG_RCV_STATUS_TRANSPORT_NFS 0x04000000 /* Transport NFS */
+#define SXG_RCV_STATUS_TRANSPORT_FTP 0x03000000 /* Transport FTP */
+#define SXG_RCV_STATUS_TRANSPORT_HTTP 0x02000000 /* Transport HTTP */
+#define SXG_RCV_STATUS_TRANSPORT_SMB 0x01000000 /* Transport SMB */
+#define SXG_RCV_STATUS_NETWORK_MASK 0x00FF0000 /* Network mask */
+#define SXG_RCV_STATUS_NETWORK_ERROR 0x00800000 /* Network error */
+/* Network cksum error */
+#define SXG_RCV_STATUS_NETWORK_CSUM 0x00830000
+/* Network underflow error */
+#define SXG_RCV_STATUS_NETWORK_UFLOW 0x00820000
+ /* Network header length */
+#define SXG_RCV_STATUS_NETWORK_HDRLEN 0x00800000
+ /* Network overflow detected */
+#define SXG_RCV_STATUS_NETWORK_OFLOW 0x00400000
+/* Network multicast detected */
+#define SXG_RCV_STATUS_NETWORK_MCAST 0x00200000
+/* Network options detected */
+#define SXG_RCV_STATUS_NETWORK_OPTIONS 0x00100000
+/* Network offset detected */
+#define SXG_RCV_STATUS_NETWORK_OFFSET 0x00080000
+/* Network fragment detected */
+#define SXG_RCV_STATUS_NETWORK_FRAGMENT 0x00040000
+/* Network transport type mask */
+#define SXG_RCV_STATUS_NETWORK_TRANS_MASK 0x00030000
+#define SXG_RCV_STATUS_NETWORK_UDP 0x00020000 /* UDP */
+#define SXG_RCV_STATUS_NETWORK_TCP 0x00010000 /* TCP */
+#define SXG_RCV_STATUS_IPONLY 0x00008000 /* IP-only not TCP */
+/* Receive priority */
+#define SXG_RCV_STATUS_PKT_PRI 0x00006000
+/* Receive priority shift */
+#define SXG_RCV_STATUS_PKT_PRI_SHFT 13
+/* MAC Receive RAM parity error */
+#define SXG_RCV_STATUS_PARITY 0x00001000
+/* Link address detection mask */
+#define SXG_RCV_STATUS_ADDRESS_MASK 0x00000F00
+
+#define SXG_RCV_STATUS_ADDRESS_D 0x00000B00 /* Link address D */
+#define SXG_RCV_STATUS_ADDRESS_C 0x00000A00 /* Link address C */
+#define SXG_RCV_STATUS_ADDRESS_B 0x00000900 /* Link address B */
+#define SXG_RCV_STATUS_ADDRESS_A 0x00000800 /* Link address A */
+/* Link address broadcast */
+#define SXG_RCV_STATUS_ADDRESS_BCAST 0x00000300
+ /* Link address multicast */
+#define SXG_RCV_STATUS_ADDRESS_MCAST 0x00000200
+/* Link control multicast */
+#define SXG_RCV_STATUS_ADDRESS_CMCAST 0x00000100
+/* Link status mask */
+#define SXG_RCV_STATUS_LINK_MASK 0x000000FF
+#define SXG_RCV_STATUS_LINK_ERROR 0x00000080 /* Link error */
+/* Link status mask */
+#define SXG_RCV_STATUS_LINK_MASK 0x000000FF
+/* RcvMacQ parity error */
+#define SXG_RCV_STATUS_LINK_PARITY 0x00000087
+#define SXG_RCV_STATUS_LINK_EARLY 0x00000086 /* Data early */
+#define SXG_RCV_STATUS_LINK_BUFOFLOW 0x00000085 /* Buffer overflow */
+#define SXG_RCV_STATUS_LINK_CODE 0x00000084 /* Link code error */
+#define SXG_RCV_STATUS_LINK_DRIBBLE 0x00000083 /* Dribble nibble */
+#define SXG_RCV_STATUS_LINK_CRC 0x00000082 /* CRC error */
+#define SXG_RCV_STATUS_LINK_OFLOW 0x00000081 /* Link overflow */
+#define SXG_RCV_STATUS_LINK_UFLOW 0x00000080 /* Link underflow */
+#define SXG_RCV_STATUS_LINK_8023 0x00000020 /* 802.3 */
+#define SXG_RCV_STATUS_LINK_SNAP 0x00000010 /* Snap */
+#define SXG_RCV_STATUS_LINK_VLAN 0x00000008 /* VLAN */
+/* Network type mask */
+#define SXG_RCV_STATUS_LINK_TYPE_MASK 0x00000007
+#define SXG_RCV_STATUS_LINK_CONTROL 0x00000003 /* Control packet */
+#define SXG_RCV_STATUS_LINK_IPV6 0x00000002 /* IPv6 packet */
+#define SXG_RCV_STATUS_LINK_IPV4 0x00000001 /* IPv4 packet */
+
+/* Sahara receive and transmit configuration registers */
+/* RcvConfig register reset */
+#define RCV_CONFIG_RESET 0x80000000
+/* Enable the receive logic */
+#define RCV_CONFIG_ENABLE 0x40000000
+/* Enable the receive parser */
+#define RCV_CONFIG_ENPARSE 0x20000000
+/* Enable the socket detector */
+#define RCV_CONFIG_SOCKET 0x10000000
+#define RCV_CONFIG_RCVBAD 0x08000000 /* Receive all bad frames */
+/* Receive all control frames */
+#define RCV_CONFIG_CONTROL 0x04000000
+/* Enable pause transmit when attn */
+#define RCV_CONFIG_RCVPAUSE 0x02000000
+/* Include TCP port w/ IPv6 toeplitz */
+#define RCV_CONFIG_TZIPV6 0x01000000
+/* Include TCP port w/ IPv4 toeplitz */
+#define RCV_CONFIG_TZIPV4 0x00800000
+#define RCV_CONFIG_FLUSH 0x00400000 /* Flush buffers */
+#define RCV_CONFIG_PRIORITY_MASK 0x00300000 /* Priority level */
+#define RCV_CONFIG_CONN_MASK 0x000C0000 /* Number of connections */
+#define RCV_CONFIG_CONN_4K 0x00000000 /* 4k connections */
+#define RCV_CONFIG_CONN_2K 0x00040000 /* 2k connections */
+#define RCV_CONFIG_CONN_1K 0x00080000 /* 1k connections */
+#define RCV_CONFIG_CONN_512 0x000C0000 /* 512 connections */
+#define RCV_CONFIG_HASH_MASK 0x00030000 /* Hash depth */
+#define RCV_CONFIG_HASH_8 0x00000000 /* Hash depth 8 */
+#define RCV_CONFIG_HASH_16 0x00010000 /* Hash depth 16 */
+#define RCV_CONFIG_HASH_4 0x00020000 /* Hash depth 4 */
+#define RCV_CONFIG_HASH_2 0x00030000 /* Hash depth 2 */
+/* Buffer length bits 15:4. ie multiple of 16. */
+#define RCV_CONFIG_BUFLEN_MASK 0x0000FFF0
+/* Disable socket detection on attn */
+#define RCV_CONFIG_SKT_DIS 0x00000008
+/*
+ * Macro to determine RCV_CONFIG_BUFLEN based on maximum frame size.
+ * We add 18 bytes for Sahara receive status and padding, plus 4 bytes for CRC,
+ * and round up to nearest 16 byte boundary
+ */
+#define RCV_CONFIG_BUFSIZE(_MaxFrame) \
+ ((((_MaxFrame) + 22) + 15) & RCV_CONFIG_BUFLEN_MASK)
+
+/* XmtConfig register reset */
+#define XMT_CONFIG_RESET 0x80000000
+#define XMT_CONFIG_ENABLE 0x40000000 /* Enable transmit logic */
+/* Inhibit MAC RAM parity error */
+#define XMT_CONFIG_MAC_PARITY 0x20000000
+/* Inhibit D2F buffer parity error */
+#define XMT_CONFIG_BUF_PARITY 0x10000000
+/* Inhibit 1T SRAM parity error */
+#define XMT_CONFIG_MEM_PARITY 0x08000000
+#define XMT_CONFIG_INVERT_PARITY 0x04000000 /* Invert MAC RAM parity */
+#define XMT_CONFIG_INITIAL_IPID 0x0000FFFF /* Initial IPID */
+
+/*
+ * A-XGMAC Registers - Occupy 0x80 - 0xD4 of the struct sxg_hw_regs
*
* Full register descriptions can be found in axgmac.pdf
- ***************************************************************************/
-// A-XGMAC Configuration Register 0
-#define AXGMAC_CFG0_SUB_RESET 0x80000000 // Sub module reset
-#define AXGMAC_CFG0_RCNTRL_RESET 0x00400000 // Receive control reset
-#define AXGMAC_CFG0_RFUNC_RESET 0x00200000 // Receive function reset
-#define AXGMAC_CFG0_TCNTRL_RESET 0x00040000 // Transmit control reset
-#define AXGMAC_CFG0_TFUNC_RESET 0x00020000 // Transmit function reset
-#define AXGMAC_CFG0_MII_RESET 0x00010000 // MII Management reset
-
-// A-XGMAC Configuration Register 1
-#define AXGMAC_CFG1_XMT_PAUSE 0x80000000 // Allow the sending of Pause frames
-#define AXGMAC_CFG1_XMT_EN 0x40000000 // Enable transmit
-#define AXGMAC_CFG1_RCV_PAUSE 0x20000000 // Allow the detection of Pause frames
-#define AXGMAC_CFG1_RCV_EN 0x10000000 // Enable receive
-#define AXGMAC_CFG1_XMT_STATE 0x04000000 // Current transmit state - READ ONLY
-#define AXGMAC_CFG1_RCV_STATE 0x01000000 // Current receive state - READ ONLY
-#define AXGMAC_CFG1_XOFF_SHORT 0x00001000 // Only pause for 64 slot on XOFF
-#define AXGMAC_CFG1_XMG_FCS1 0x00000400 // Delay transmit FCS 1 4-byte word
-#define AXGMAC_CFG1_XMG_FCS2 0x00000800 // Delay transmit FCS 2 4-byte words
-#define AXGMAC_CFG1_XMG_FCS3 0x00000C00 // Delay transmit FCS 3 4-byte words
-#define AXGMAC_CFG1_RCV_FCS1 0x00000100 // Delay receive FCS 1 4-byte word
-#define AXGMAC_CFG1_RCV_FCS2 0x00000200 // Delay receive FCS 2 4-byte words
-#define AXGMAC_CFG1_RCV_FCS3 0x00000300 // Delay receive FCS 3 4-byte words
-#define AXGMAC_CFG1_PKT_OVERRIDE 0x00000080 // Per-packet override enable
-#define AXGMAC_CFG1_SWAP 0x00000040 // Byte swap enable
-#define AXGMAC_CFG1_SHORT_ASSERT 0x00000020 // ASSERT srdrpfrm on short frame (<64)
-#define AXGMAC_CFG1_RCV_STRICT 0x00000010 // RCV only 802.3AE when CLEAR
-#define AXGMAC_CFG1_CHECK_LEN 0x00000008 // Verify frame length
-#define AXGMAC_CFG1_GEN_FCS 0x00000004 // Generate FCS
-#define AXGMAC_CFG1_PAD_MASK 0x00000003 // Mask for pad bits
-#define AXGMAC_CFG1_PAD_64 0x00000001 // Pad frames to 64 bytes
-#define AXGMAC_CFG1_PAD_VLAN 0x00000002 // Detect VLAN and pad to 68 bytes
-#define AXGMAC_CFG1_PAD_68 0x00000003 // Pad to 68 bytes
-
-// A-XGMAC Configuration Register 2
-#define AXGMAC_CFG2_GEN_PAUSE 0x80000000 // Generate single pause frame (test)
-#define AXGMAC_CFG2_LF_MANUAL 0x08000000 // Manual link fault sequence
-#define AXGMAC_CFG2_LF_AUTO 0x04000000 // Auto link fault sequence
-#define AXGMAC_CFG2_LF_REMOTE 0x02000000 // Remote link fault (READ ONLY)
-#define AXGMAC_CFG2_LF_LOCAL 0x01000000 // Local link fault (READ ONLY)
-#define AXGMAC_CFG2_IPG_MASK 0x001F0000 // Inter packet gap
+ */
+/* A-XGMAC Configuration Register 0 */
+#define AXGMAC_CFG0_SUB_RESET 0x80000000 /* Sub module reset */
+#define AXGMAC_CFG0_RCNTRL_RESET 0x00400000 /* Receive control reset */
+#define AXGMAC_CFG0_RFUNC_RESET 0x00200000 /* Receive function reset */
+#define AXGMAC_CFG0_TCNTRL_RESET 0x00040000 /* Transmit control reset */
+#define AXGMAC_CFG0_TFUNC_RESET 0x00020000 /* Transmit function reset */
+#define AXGMAC_CFG0_MII_RESET 0x00010000 /* MII Management reset */
+
+/* A-XGMAC Configuration Register 1 */
+/* Allow the sending of Pause frames */
+#define AXGMAC_CFG1_XMT_PAUSE 0x80000000
+#define AXGMAC_CFG1_XMT_EN 0x40000000 /* Enable transmit */
+/* Allow the detection of Pause frames */
+#define AXGMAC_CFG1_RCV_PAUSE 0x20000000
+#define AXGMAC_CFG1_RCV_EN 0x10000000 /* Enable receive */
+/* Current transmit state - READ ONLY */
+#define AXGMAC_CFG1_XMT_STATE 0x04000000
+/* Current receive state - READ ONLY */
+#define AXGMAC_CFG1_RCV_STATE 0x01000000
+/* Only pause for 64 slot on XOFF */
+#define AXGMAC_CFG1_XOFF_SHORT 0x00001000
+/* Delay transmit FCS 1 4-byte word */
+#define AXGMAC_CFG1_XMG_FCS1 0x00000400
+/* Delay transmit FCS 2 4-byte words */
+#define AXGMAC_CFG1_XMG_FCS2 0x00000800
+/* Delay transmit FCS 3 4-byte words */
+#define AXGMAC_CFG1_XMG_FCS3 0x00000C00
+/* Delay receive FCS 1 4-byte word */
+#define AXGMAC_CFG1_RCV_FCS1 0x00000100
+/* Delay receive FCS 2 4-byte words */
+#define AXGMAC_CFG1_RCV_FCS2 0x00000200
+/* Delay receive FCS 3 4-byte words */
+#define AXGMAC_CFG1_RCV_FCS3 0x00000300
+/* Per-packet override enable */
+#define AXGMAC_CFG1_PKT_OVERRIDE 0x00000080
+#define AXGMAC_CFG1_SWAP 0x00000040 /* Byte swap enable */
+/* ASSERT srdrpfrm on short frame (<64) */
+#define AXGMAC_CFG1_SHORT_ASSERT 0x00000020
+/* RCV only 802.3AE when CLEAR */
+#define AXGMAC_CFG1_RCV_STRICT 0x00000010
+#define AXGMAC_CFG1_CHECK_LEN 0x00000008 /* Verify frame length */
+#define AXGMAC_CFG1_GEN_FCS 0x00000004 /* Generate FCS */
+#define AXGMAC_CFG1_PAD_MASK 0x00000003 /* Mask for pad bits */
+#define AXGMAC_CFG1_PAD_64 0x00000001 /* Pad frames to 64 bytes */
+/* Detect VLAN and pad to 68 bytes */
+#define AXGMAC_CFG1_PAD_VLAN 0x00000002
+#define AXGMAC_CFG1_PAD_68 0x00000003 /* Pad to 68 bytes */
+
+/* A-XGMAC Configuration Register 2 */
+/* Generate single pause frame (test) */
+#define AXGMAC_CFG2_GEN_PAUSE 0x80000000
+/* Manual link fault sequence */
+#define AXGMAC_CFG2_LF_MANUAL 0x08000000
+/* Auto link fault sequence */
+#define AXGMAC_CFG2_LF_AUTO 0x04000000
+/* Remote link fault (READ ONLY) */
+#define AXGMAC_CFG2_LF_REMOTE 0x02000000
+/* Local link fault (READ ONLY) */
+#define AXGMAC_CFG2_LF_LOCAL 0x01000000
+#define AXGMAC_CFG2_IPG_MASK 0x001F0000 /* Inter packet gap */
#define AXGMAC_CFG2_IPG_SHIFT 16
-#define AXGMAC_CFG2_PAUSE_XMT 0x00008000 // Pause transmit module
-#define AXGMAC_CFG2_IPG_EXTEN 0x00000020 // Enable IPG extension algorithm
-#define AXGMAC_CFG2_IPGEX_MASK 0x0000001F // IPG extension
-
-// A-XGMAC Configuration Register 3
-#define AXGMAC_CFG3_RCV_DROP 0xFFFF0000 // Receive frame drop filter
-#define AXGMAC_CFG3_RCV_DONT_CARE 0x0000FFFF // Receive frame don't care filter
-
-// A-XGMAC Station Address Register - Octets 1-4
-#define AXGMAC_SARLOW_OCTET_ONE 0xFF000000 // First octet
-#define AXGMAC_SARLOW_OCTET_TWO 0x00FF0000 // Second octet
-#define AXGMAC_SARLOW_OCTET_THREE 0x0000FF00 // Third octet
-#define AXGMAC_SARLOW_OCTET_FOUR 0x000000FF // Fourth octet
-
-// A-XGMAC Station Address Register - Octets 5-6
-#define AXGMAC_SARHIGH_OCTET_FIVE 0xFF000000 // Fifth octet
-#define AXGMAC_SARHIGH_OCTET_SIX 0x00FF0000 // Sixth octet
-
-// A-XGMAC Maximum frame length register
-#define AXGMAC_MAXFRAME_XMT 0x3FFF0000 // Maximum transmit frame length
+#define AXGMAC_CFG2_PAUSE_XMT 0x00008000 /* Pause transmit module */
+/* Enable IPG extension algorithm */
+#define AXGMAC_CFG2_IPG_EXTEN 0x00000020
+#define AXGMAC_CFG2_IPGEX_MASK 0x0000001F /* IPG extension */
+
+/* A-XGMAC Configuration Register 3 */
+/* Receive frame drop filter */
+#define AXGMAC_CFG3_RCV_DROP 0xFFFF0000
+/* Receive frame don't care filter */
+#define AXGMAC_CFG3_RCV_DONT_CARE 0x0000FFFF
+
+/* A-XGMAC Station Address Register - Octets 1-4 */
+#define AXGMAC_SARLOW_OCTET_ONE 0xFF000000 /* First octet */
+#define AXGMAC_SARLOW_OCTET_TWO 0x00FF0000 /* Second octet */
+#define AXGMAC_SARLOW_OCTET_THREE 0x0000FF00 /* Third octet */
+#define AXGMAC_SARLOW_OCTET_FOUR 0x000000FF /* Fourth octet */
+
+/* A-XGMAC Station Address Register - Octets 5-6 */
+#define AXGMAC_SARHIGH_OCTET_FIVE 0xFF000000 /* Fifth octet */
+#define AXGMAC_SARHIGH_OCTET_SIX 0x00FF0000 /* Sixth octet */
+
+/* A-XGMAC Maximum frame length register */
+/* Maximum transmit frame length */
+#define AXGMAC_MAXFRAME_XMT 0x3FFF0000
#define AXGMAC_MAXFRAME_XMT_SHIFT 16
-#define AXGMAC_MAXFRAME_RCV 0x0000FFFF // Maximum receive frame length
-// This register doesn't need to be written for standard MTU.
-// For jumbo, I'll just statically define the value here. This
-// value sets the receive byte count to 9036 (0x234C) and the
-// transmit WORD count to 2259 (0x8D3). These values include 22
-// bytes of padding beyond the jumbo MTU of 9014
+/* Maximum receive frame length */
+#define AXGMAC_MAXFRAME_RCV 0x0000FFFF
+/*
+ * This register doesn't need to be written for standard MTU.
+ * For jumbo, I'll just statically define the value here. This
+ * value sets the receive byte count to 9036 (0x234C) and the
+ * transmit WORD count to 2259 (0x8D3). These values include 22
+ * bytes of padding beyond the jumbo MTU of 9014
+ */
#define AXGMAC_MAXFRAME_JUMBO 0x08D3234C
-// A-XGMAC Revision level
-#define AXGMAC_REVISION_MASK 0x0000FFFF // Revision level
-
-// A-XGMAC AMIIM Command Register
-#define AXGMAC_AMIIM_CMD_START 0x00000008 // Command start
-#define AXGMAC_AMIIM_CMD_MASK 0x00000007 // Command
-#define AXGMAC_AMIIM_CMD_LEGACY_WRITE 1 // 10/100/1000 Mbps Phy Write
-#define AXGMAC_AMIIM_CMD_LEGACY_READ 2 // 10/100/1000 Mbps Phy Read
-#define AXGMAC_AMIIM_CMD_MONITOR_SINGLE 3 // Monitor single PHY
-#define AXGMAC_AMIIM_CMD_MONITOR_MULTIPLE 4 // Monitor multiple contiguous PHYs
-#define AXGMAC_AMIIM_CMD_10G_OPERATION 5 // Present AMIIM Field Reg
-#define AXGMAC_AMIIM_CMD_CLEAR_LINK_FAIL 6 // Clear Link Fail Bit in MIIM
-
-// A-XGMAC AMIIM Field Register
-#define AXGMAC_AMIIM_FIELD_ST 0xC0000000 // 2-bit ST field
+/* A-XGMAC Revision level */
+#define AXGMAC_REVISION_MASK 0x0000FFFF /* Revision level */
+
+/* A-XGMAC AMIIM Command Register */
+#define AXGMAC_AMIIM_CMD_START 0x00000008 /* Command start */
+#define AXGMAC_AMIIM_CMD_MASK 0x00000007 /* Command */
+/* 10/100/1000 Mbps Phy Write */
+#define AXGMAC_AMIIM_CMD_LEGACY_WRITE 1
+/* 10/100/1000 Mbps Phy Read */
+#define AXGMAC_AMIIM_CMD_LEGACY_READ 2
+#define AXGMAC_AMIIM_CMD_MONITOR_SINGLE 3 /* Monitor single PHY */
+/* Monitor multiple contiguous PHYs */
+#define AXGMAC_AMIIM_CMD_MONITOR_MULTIPLE 4
+/* Present AMIIM Field Reg */
+#define AXGMAC_AMIIM_CMD_10G_OPERATION 5
+/* Clear Link Fail Bit in MIIM */
+#define AXGMAC_AMIIM_CMD_CLEAR_LINK_FAIL 6
+
+/* A-XGMAC AMIIM Field Register */
+#define AXGMAC_AMIIM_FIELD_ST 0xC0000000 /* 2-bit ST field */
#define AXGMAC_AMIIM_FIELD_ST_SHIFT 30
-#define AXGMAC_AMIIM_FIELD_OP 0x30000000 // 2-bit OP field
+#define AXGMAC_AMIIM_FIELD_OP 0x30000000 /* 2-bit OP field */
#define AXGMAC_AMIIM_FIELD_OP_SHIFT 28
-#define AXGMAC_AMIIM_FIELD_PORT_ADDR 0x0F800000 // Port address field (hstphyadx in spec)
+/* Port address field (hstphyadx in spec) */
+#define AXGMAC_AMIIM_FIELD_PORT_ADDR 0x0F800000
#define AXGMAC_AMIIM_FIELD_PORT_SHIFT 23
-#define AXGMAC_AMIIM_FIELD_DEV_ADDR 0x007C0000 // Device address field (hstregadx in spec)
+/* Device address field (hstregadx in spec) */
+#define AXGMAC_AMIIM_FIELD_DEV_ADDR 0x007C0000
#define AXGMAC_AMIIM_FIELD_DEV_SHIFT 18
-#define AXGMAC_AMIIM_FIELD_TA 0x00030000 // 2-bit TA field
+#define AXGMAC_AMIIM_FIELD_TA 0x00030000 /* 2-bit TA field */
#define AXGMAC_AMIIM_FIELD_TA_SHIFT 16
-#define AXGMAC_AMIIM_FIELD_DATA 0x0000FFFF // Data field
+#define AXGMAC_AMIIM_FIELD_DATA 0x0000FFFF /* Data field */
-// Values for the AXGMAC_AMIIM_FIELD_OP field in the A-XGMAC AMIIM Field Register
-#define MIIM_OP_ADDR 0 // MIIM Address set operation
-#define MIIM_OP_WRITE 1 // MIIM Write register operation
-#define MIIM_OP_READ 2 // MIIM Read register operation
+/* Values for the AXGMAC_AMIIM_FIELD_OP field in the A-XGMAC AMIIM Field Register */
+#define MIIM_OP_ADDR 0 /* MIIM Address set operation */
+#define MIIM_OP_WRITE 1 /* MIIM Write register operation */
+#define MIIM_OP_READ 2 /* MIIM Read register operation */
#define MIIM_OP_ADDR_SHIFT (MIIM_OP_ADDR << AXGMAC_AMIIM_FIELD_OP_SHIFT)
-// Values for the AXGMAC_AMIIM_FIELD_PORT_ADDR field in the A-XGMAC AMIIM Field Register
-#define MIIM_PORT_NUM 1 // All Sahara MIIM modules use port 1
-
-// Values for the AXGMAC_AMIIM_FIELD_DEV_ADDR field in the A-XGMAC AMIIM Field Register
-#define MIIM_DEV_PHY_PMA 1 // PHY PMA/PMD module MIIM device number
-#define MIIM_DEV_PHY_PCS 3 // PHY PCS module MIIM device number
-#define MIIM_DEV_PHY_XS 4 // PHY XS module MIIM device number
-#define MIIM_DEV_XGXS 5 // XGXS MIIM device number
-
-// Values for the AXGMAC_AMIIM_FIELD_TA field in the A-XGMAC AMIIM Field Register
-#define MIIM_TA_10GB 2 // set to 2 for 10 GB operation
-
-// A-XGMAC AMIIM Configuration Register
-#define AXGMAC_AMIIM_CFG_NOPREAM 0x00000080 // Bypass preamble of mngmt frame
-#define AXGMAC_AMIIM_CFG_HALF_CLOCK 0x0000007F // half-clock duration of MDC output
-
-// A-XGMAC AMIIM Indicator Register
-#define AXGMAC_AMIIM_INDC_LINK 0x00000010 // Link status from legacy PHY or MMD
-#define AXGMAC_AMIIM_INDC_MPHY 0x00000008 // Multiple phy operation in progress
-#define AXGMAC_AMIIM_INDC_SPHY 0x00000004 // Single phy operation in progress
-#define AXGMAC_AMIIM_INDC_MON 0x00000002 // Single or multiple monitor cmd
-#define AXGMAC_AMIIM_INDC_BUSY 0x00000001 // Set until cmd operation complete
-
-// Link Status and Control Register
-#define LS_PHY_CLR_RESET 0x80000000 // Clear reset signal to PHY
-#define LS_SERDES_POWER_DOWN 0x40000000 // Power down the Sahara Serdes
-#define LS_XGXS_ENABLE 0x20000000 // Enable the XAUI XGXS logic
-#define LS_XGXS_CTL 0x10000000 // Hold XAUI XGXS logic reset until Serdes is up
-#define LS_SERDES_DOWN 0x08000000 // When 0, XAUI Serdes is up and initialization is complete
-#define LS_TRACE_DOWN 0x04000000 // When 0, Trace Serdes is up and initialization is complete
-#define LS_PHY_CLK_25MHZ 0x02000000 // Set PHY clock to 25 MHz (else 156.125 MHz)
-#define LS_PHY_CLK_EN 0x01000000 // Enable clock to PHY
-#define LS_XAUI_LINK_UP 0x00000010 // XAUI link is up
-#define LS_XAUI_LINK_CHNG 0x00000008 // XAUI link status has changed
-#define LS_LINK_ALARM 0x00000004 // Link alarm pin
-#define LS_ATTN_CTRL_MASK 0x00000003 // Mask link attention control bits
-#define LS_ATTN_ALARM 0x00000000 // 00 => Attn on link alarm
-#define LS_ATTN_ALARM_OR_STAT_CHNG 0x00000001 // 01 => Attn on link alarm or status change
-#define LS_ATTN_STAT_CHNG 0x00000002 // 10 => Attn on link status change
-#define LS_ATTN_NONE 0x00000003 // 11 => no Attn
-
-// Link Address High Registers
-#define LINK_ADDR_ENABLE 0x80000000 // Enable this link address
-
-
-/***************************************************************************
+/*
+ * Values for the AXGMAC_AMIIM_FIELD_PORT_ADDR field in the A-XGMAC AMIIM
+ * Field Register
+ */
+#define MIIM_PORT_NUM 1 /* All Sahara MIIM modules use port 1 */
+
+/*
+ * Values for the AXGMAC_AMIIM_FIELD_DEV_ADDR field in the A-XGMAC AMIIM
+ * Field Register
+ */
+/* PHY PMA/PMD module MIIM device number */
+#define MIIM_DEV_PHY_PMA 1
+/* PHY PCS module MIIM device number */
+#define MIIM_DEV_PHY_PCS 3
+/* PHY XS module MIIM device number */
+#define MIIM_DEV_PHY_XS 4
+#define MIIM_DEV_XGXS 5 /* XGXS MIIM device number */
+
+/*
+ * Values for the AXGMAC_AMIIM_FIELD_TA field in the A-XGMAC AMIIM Field
+ * Register
+ */
+#define MIIM_TA_10GB 2 /* set to 2 for 10 GB operation */
+
+/* A-XGMAC AMIIM Configuration Register */
+/* Bypass preamble of mngmt frame */
+#define AXGMAC_AMIIM_CFG_NOPREAM 0x00000080
+/* half-clock duration of MDC output */
+#define AXGMAC_AMIIM_CFG_HALF_CLOCK 0x0000007F
+
+/* A-XGMAC AMIIM Indicator Register */
+/* Link status from legacy PHY or MMD */
+#define AXGMAC_AMIIM_INDC_LINK 0x00000010
+/* Multiple phy operation in progress */
+#define AXGMAC_AMIIM_INDC_MPHY 0x00000008
+/* Single phy operation in progress */
+#define AXGMAC_AMIIM_INDC_SPHY 0x00000004
+/* Single or multiple monitor cmd */
+#define AXGMAC_AMIIM_INDC_MON 0x00000002
+/* Set until cmd operation complete */
+#define AXGMAC_AMIIM_INDC_BUSY 0x00000001
+
+/* Link Status and Control Register */
+#define LS_PHY_CLR_RESET 0x80000000 /* Clear reset signal to PHY */
+#define LS_SERDES_POWER_DOWN 0x40000000 /* Power down the Sahara Serdes */
+#define LS_XGXS_ENABLE 0x20000000 /* Enable the XAUI XGXS logic */
+/* Hold XAUI XGXS logic reset until Serdes is up */
+#define LS_XGXS_CTL 0x10000000
+/* When 0, XAUI Serdes is up and initialization is complete */
+#define LS_SERDES_DOWN 0x08000000
+/* When 0, Trace Serdes is up and initialization is complete */
+#define LS_TRACE_DOWN 0x04000000
+/* Set PHY clock to 25 MHz (else 156.125 MHz) */
+#define LS_PHY_CLK_25MHZ 0x02000000
+#define LS_PHY_CLK_EN 0x01000000 /* Enable clock to PHY */
+#define LS_XAUI_LINK_UP 0x00000010 /* XAUI link is up */
+/* XAUI link status has changed */
+#define LS_XAUI_LINK_CHNG 0x00000008
+#define LS_LINK_ALARM 0x00000004 /* Link alarm pin */
+/* Mask link attention control bits */
+#define LS_ATTN_CTRL_MASK 0x00000003
+#define LS_ATTN_ALARM 0x00000000 /* 00 => Attn on link alarm */
+/* 01 => Attn on link alarm or status change */
+#define LS_ATTN_ALARM_OR_STAT_CHNG 0x00000001
+/* 10 => Attn on link status change */
+#define LS_ATTN_STAT_CHNG 0x00000002
+#define LS_ATTN_NONE 0x00000003 /* 11 => no Attn */
+
+/* Link Address High Registers */
+#define LINK_ADDR_ENABLE 0x80000000 /* Enable this link address */
+
+
+/*
* XGXS XAUI XGMII Extender registers
*
* Full register descriptions can be found in mxgxs.pdf
- ***************************************************************************/
-// XGXS Register Map
-#define XGXS_ADDRESS_CONTROL1 0x0000 // XS Control 1
-#define XGXS_ADDRESS_STATUS1 0x0001 // XS Status 1
-#define XGXS_ADDRESS_DEVID_LOW 0x0002 // XS Device ID (low)
-#define XGXS_ADDRESS_DEVID_HIGH 0x0003 // XS Device ID (high)
-#define XGXS_ADDRESS_SPEED 0x0004 // XS Speed ability
-#define XGXS_ADDRESS_DEV_LOW 0x0005 // XS Devices in package
-#define XGXS_ADDRESS_DEV_HIGH 0x0006 // XS Devices in package
-#define XGXS_ADDRESS_STATUS2 0x0008 // XS Status 2
-#define XGXS_ADDRESS_PKGID_lOW 0x000E // XS Package Identifier
-#define XGXS_ADDRESS_PKGID_HIGH 0x000F // XS Package Identifier
-#define XGXS_ADDRESS_LANE_STATUS 0x0018 // 10G XGXS Lane Status
-#define XGXS_ADDRESS_TEST_CTRL 0x0019 // 10G XGXS Test Control
-#define XGXS_ADDRESS_RESET_LO1 0x8000 // Vendor-Specific Reset Lo 1
-#define XGXS_ADDRESS_RESET_LO2 0x8001 // Vendor-Specific Reset Lo 2
-#define XGXS_ADDRESS_RESET_HI1 0x8002 // Vendor-Specific Reset Hi 1
-#define XGXS_ADDRESS_RESET_HI2 0x8003 // Vendor-Specific Reset Hi 2
-
-// XS Control 1 register bit definitions
-#define XGXS_CONTROL1_RESET 0x8000 // Reset - self clearing
-#define XGXS_CONTROL1_LOOPBACK 0x4000 // Enable loopback
-#define XGXS_CONTROL1_SPEED1 0x2000 // 0 = unspecified, 1 = 10Gb+
-#define XGXS_CONTROL1_LOWPOWER 0x0400 // 1 = Low power mode
-#define XGXS_CONTROL1_SPEED2 0x0040 // Same as SPEED1 (?)
-#define XGXS_CONTROL1_SPEED 0x003C // Everything reserved except zero (?)
-
-// XS Status 1 register bit definitions
-#define XGXS_STATUS1_FAULT 0x0080 // Fault detected
-#define XGXS_STATUS1_LINK 0x0004 // 1 = Link up
-#define XGXS_STATUS1_LOWPOWER 0x0002 // 1 = Low power supported
-
-// XS Speed register bit definitions
-#define XGXS_SPEED_10G 0x0001 // 1 = 10G capable
-
-// XS Devices register bit definitions
-#define XGXS_DEVICES_DTE 0x0020 // DTE XS Present
-#define XGXS_DEVICES_PHY 0x0010 // PHY XS Present
-#define XGXS_DEVICES_PCS 0x0008 // PCS Present
-#define XGXS_DEVICES_WIS 0x0004 // WIS Present
-#define XGXS_DEVICES_PMD 0x0002 // PMD/PMA Present
-#define XGXS_DEVICES_CLAUSE22 0x0001 // Clause 22 registers present
-
-// XS Devices High register bit definitions
-#define XGXS_DEVICES_VENDOR2 0x8000 // Vendor specific device 2
-#define XGXS_DEVICES_VENDOR1 0x4000 // Vendor specific device 1
-
-// XS Status 2 register bit definitions
-#define XGXS_STATUS2_DEV_MASK 0xC000 // Device present mask
-#define XGXS_STATUS2_DEV_RESPOND 0x8000 // Device responding
-#define XGXS_STATUS2_XMT_FAULT 0x0800 // Transmit fault
-#define XGXS_STATUS2_RCV_FAULT 0x0400 // Receive fault
-
-// XS Package ID High register bit definitions
-#define XGXS_PKGID_HIGH_ORG 0xFC00 // Organizationally Unique
-#define XGXS_PKGID_HIGH_MFG 0x03F0 // Manufacturer Model
-#define XGXS_PKGID_HIGH_REV 0x000F // Revision Number
-
-// XS Lane Status register bit definitions
-#define XGXS_LANE_PHY 0x1000 // PHY/DTE lane alignment status
-#define XGXS_LANE_PATTERN 0x0800 // Pattern testing ability
-#define XGXS_LANE_LOOPBACK 0x0400 // PHY loopback ability
-#define XGXS_LANE_SYNC3 0x0008 // Lane 3 sync
-#define XGXS_LANE_SYNC2 0x0004 // Lane 2 sync
-#define XGXS_LANE_SYNC1 0x0002 // Lane 1 sync
-#define XGXS_LANE_SYNC0 0x0001 // Lane 0 sync
-
-// XS Test Control register bit definitions
-#define XGXS_TEST_PATTERN_ENABLE 0x0004 // Test pattern enabled
-#define XGXS_TEST_PATTERN_MASK 0x0003 // Test patterns
-#define XGXS_TEST_PATTERN_RSVD 0x0003 // Test pattern - reserved
-#define XGXS_TEST_PATTERN_MIX 0x0002 // Test pattern - mixed
-#define XGXS_TEST_PATTERN_LOW 0x0001 // Test pattern - low
-#define XGXS_TEST_PATTERN_HIGH 0x0001 // Test pattern - high
-
-/***************************************************************************
+ */
+/* XGXS Register Map */
+#define XGXS_ADDRESS_CONTROL1 0x0000 /* XS Control 1 */
+#define XGXS_ADDRESS_STATUS1 0x0001 /* XS Status 1 */
+#define XGXS_ADDRESS_DEVID_LOW 0x0002 /* XS Device ID (low) */
+#define XGXS_ADDRESS_DEVID_HIGH 0x0003 /* XS Device ID (high) */
+#define XGXS_ADDRESS_SPEED 0x0004 /* XS Speed ability */
+#define XGXS_ADDRESS_DEV_LOW 0x0005 /* XS Devices in package */
+#define XGXS_ADDRESS_DEV_HIGH 0x0006 /* XS Devices in package */
+#define XGXS_ADDRESS_STATUS2 0x0008 /* XS Status 2 */
+#define XGXS_ADDRESS_PKGID_lOW 0x000E /* XS Package Identifier */
+#define XGXS_ADDRESS_PKGID_HIGH 0x000F /* XS Package Identifier */
+#define XGXS_ADDRESS_LANE_STATUS 0x0018 /* 10G XGXS Lane Status */
+#define XGXS_ADDRESS_TEST_CTRL 0x0019 /* 10G XGXS Test Control */
+#define XGXS_ADDRESS_RESET_LO1 0x8000 /* Vendor-Specific Reset Lo 1 */
+#define XGXS_ADDRESS_RESET_LO2 0x8001 /* Vendor-Specific Reset Lo 2 */
+#define XGXS_ADDRESS_RESET_HI1 0x8002 /* Vendor-Specific Reset Hi 1 */
+#define XGXS_ADDRESS_RESET_HI2 0x8003 /* Vendor-Specific Reset Hi 2 */
+
+/* XS Control 1 register bit definitions */
+#define XGXS_CONTROL1_RESET 0x8000 /* Reset - self clearing */
+#define XGXS_CONTROL1_LOOPBACK 0x4000 /* Enable loopback */
+#define XGXS_CONTROL1_SPEED1 0x2000 /* 0 = unspecified, 1 = 10Gb+ */
+#define XGXS_CONTROL1_LOWPOWER 0x0400 /* 1 = Low power mode */
+#define XGXS_CONTROL1_SPEED2 0x0040 /* Same as SPEED1 (?) */
+/* Everything reserved except zero (?) */
+#define XGXS_CONTROL1_SPEED 0x003C
+
+/* XS Status 1 register bit definitions */
+#define XGXS_STATUS1_FAULT 0x0080 /* Fault detected */
+#define XGXS_STATUS1_LINK 0x0004 /* 1 = Link up */
+#define XGXS_STATUS1_LOWPOWER 0x0002 /* 1 = Low power supported */
+
+/* XS Speed register bit definitions */
+#define XGXS_SPEED_10G 0x0001 /* 1 = 10G capable */
+
+/* XS Devices register bit definitions */
+#define XGXS_DEVICES_DTE 0x0020 /* DTE XS Present */
+#define XGXS_DEVICES_PHY 0x0010 /* PHY XS Present */
+#define XGXS_DEVICES_PCS 0x0008 /* PCS Present */
+#define XGXS_DEVICES_WIS 0x0004 /* WIS Present */
+#define XGXS_DEVICES_PMD 0x0002 /* PMD/PMA Present */
+#define XGXS_DEVICES_CLAUSE22 0x0001 /* Clause 22 registers present*/
+
+/* XS Devices High register bit definitions */
+#define XGXS_DEVICES_VENDOR2 0x8000 /* Vendor specific device 2 */
+#define XGXS_DEVICES_VENDOR1 0x4000 /* Vendor specific device 1 */
+
+/* XS Status 2 register bit definitions */
+#define XGXS_STATUS2_DEV_MASK 0xC000 /* Device present mask */
+#define XGXS_STATUS2_DEV_RESPOND 0x8000 /* Device responding */
+#define XGXS_STATUS2_XMT_FAULT 0x0800 /* Transmit fault */
+#define XGXS_STATUS2_RCV_FAULT 0x0400 /* Receive fault */
+
+/* XS Package ID High register bit definitions */
+#define XGXS_PKGID_HIGH_ORG 0xFC00 /* Organizationally Unique */
+#define XGXS_PKGID_HIGH_MFG 0x03F0 /* Manufacturer Model */
+#define XGXS_PKGID_HIGH_REV 0x000F /* Revision Number */
+
+/* XS Lane Status register bit definitions */
+#define XGXS_LANE_PHY 0x1000 /* PHY/DTE lane alignment status */
+#define XGXS_LANE_PATTERN 0x0800 /* Pattern testing ability */
+#define XGXS_LANE_LOOPBACK 0x0400 /* PHY loopback ability */
+#define XGXS_LANE_SYNC3 0x0008 /* Lane 3 sync */
+#define XGXS_LANE_SYNC2 0x0004 /* Lane 2 sync */
+#define XGXS_LANE_SYNC1 0x0002 /* Lane 1 sync */
+#define XGXS_LANE_SYNC0 0x0001 /* Lane 0 sync */
+
+/* XS Test Control register bit definitions */
+#define XGXS_TEST_PATTERN_ENABLE 0x0004 /* Test pattern enabled */
+#define XGXS_TEST_PATTERN_MASK 0x0003 /* Test patterns */
+#define XGXS_TEST_PATTERN_RSVD 0x0003 /* Test pattern - reserved */
+#define XGXS_TEST_PATTERN_MIX 0x0002 /* Test pattern - mixed */
+#define XGXS_TEST_PATTERN_LOW 0x0001 /* Test pattern - low */
+#define XGXS_TEST_PATTERN_HIGH 0x0001 /* Test pattern - high */
+
+/*
* External MDIO Bus Registers
*
* Full register descriptions can be found in PHY/XENPAK/IEEE specs
- ***************************************************************************/
-// LASI (Link Alarm Status Interrupt) Registers (located in MIIM_DEV_PHY_PMA device)
-#define LASI_RX_ALARM_CONTROL 0x9000 // LASI RX_ALARM Control
-#define LASI_TX_ALARM_CONTROL 0x9001 // LASI TX_ALARM Control
-#define LASI_CONTROL 0x9002 // LASI Control
-#define LASI_RX_ALARM_STATUS 0x9003 // LASI RX_ALARM Status
-#define LASI_TX_ALARM_STATUS 0x9004 // LASI TX_ALARM Status
-#define LASI_STATUS 0x9005 // LASI Status
-
-// LASI_CONTROL bit definitions
-#define LASI_CTL_RX_ALARM_ENABLE 0x0004 // Enable RX_ALARM interrupts
-#define LASI_CTL_TX_ALARM_ENABLE 0x0002 // Enable TX_ALARM interrupts
-#define LASI_CTL_LS_ALARM_ENABLE 0x0001 // Enable Link Status interrupts
-
-// LASI_STATUS bit definitions
-#define LASI_STATUS_RX_ALARM 0x0004 // RX_ALARM status
-#define LASI_STATUS_TX_ALARM 0x0002 // TX_ALARM status
-#define LASI_STATUS_LS_ALARM 0x0001 // Link Status
-
-// PHY registers - PMA/PMD (device 1)
-#define PHY_PMA_CONTROL1 0x0000 // PMA/PMD Control 1
-#define PHY_PMA_STATUS1 0x0001 // PMA/PMD Status 1
-#define PHY_PMA_RCV_DET 0x000A // PMA/PMD Receive Signal Detect
- // other PMA/PMD registers exist and can be defined as needed
-
-// PHY registers - PCS (device 3)
-#define PHY_PCS_CONTROL1 0x0000 // PCS Control 1
-#define PHY_PCS_STATUS1 0x0001 // PCS Status 1
-#define PHY_PCS_10G_STATUS1 0x0020 // PCS 10GBASE-R Status 1
- // other PCS registers exist and can be defined as needed
-
-// PHY registers - XS (device 4)
-#define PHY_XS_CONTROL1 0x0000 // XS Control 1
-#define PHY_XS_STATUS1 0x0001 // XS Status 1
-#define PHY_XS_LANE_STATUS 0x0018 // XS Lane Status
- // other XS registers exist and can be defined as needed
-
-// PHY_PMA_CONTROL1 register bit definitions
-#define PMA_CONTROL1_RESET 0x8000 // PMA/PMD reset
-
-// PHY_PMA_RCV_DET register bit definitions
-#define PMA_RCV_DETECT 0x0001 // PMA/PMD receive signal detect
-
-// PHY_PCS_10G_STATUS1 register bit definitions
-#define PCS_10B_BLOCK_LOCK 0x0001 // PCS 10GBASE-R locked to receive blocks
-
-// PHY_XS_LANE_STATUS register bit definitions
-#define XS_LANE_ALIGN 0x1000 // XS transmit lanes aligned
-
-// PHY Microcode download data structure
-struct PHY_UCODE {
+ */
+/*
+ * LASI (Link Alarm Status Interrupt) Registers (located in
+ * MIIM_DEV_PHY_PMA device)
+ */
+#define LASI_RX_ALARM_CONTROL 0x9000 /* LASI RX_ALARM Control */
+#define LASI_TX_ALARM_CONTROL 0x9001 /* LASI TX_ALARM Control */
+#define LASI_CONTROL 0x9002 /* LASI Control */
+#define LASI_RX_ALARM_STATUS 0x9003 /* LASI RX_ALARM Status */
+#define LASI_TX_ALARM_STATUS 0x9004 /* LASI TX_ALARM Status */
+#define LASI_STATUS 0x9005 /* LASI Status */
+
+/* LASI_CONTROL bit definitions */
+/* Enable RX_ALARM interrupts */
+#define LASI_CTL_RX_ALARM_ENABLE 0x0004
+/* Enable TX_ALARM interrupts */
+#define LASI_CTL_TX_ALARM_ENABLE 0x0002
+/* Enable Link Status interrupts */
+#define LASI_CTL_LS_ALARM_ENABLE 0x0001
+
+/* LASI_STATUS bit definitions */
+#define LASI_STATUS_RX_ALARM 0x0004 /* RX_ALARM status */
+#define LASI_STATUS_TX_ALARM 0x0002 /* TX_ALARM status */
+#define LASI_STATUS_LS_ALARM 0x0001 /* Link Status */
+
+/* PHY registers - PMA/PMD (device 1) */
+#define PHY_PMA_CONTROL1 0x0000 /* PMA/PMD Control 1 */
+#define PHY_PMA_STATUS1 0x0001 /* PMA/PMD Status 1 */
+#define PHY_PMA_RCV_DET 0x000A /* PMA/PMD Receive Signal Detect */
+ /* other PMA/PMD registers exist and can be defined as needed */
+
+/* PHY registers - PCS (device 3) */
+#define PHY_PCS_CONTROL1 0x0000 /* PCS Control 1 */
+#define PHY_PCS_STATUS1 0x0001 /* PCS Status 1 */
+#define PHY_PCS_10G_STATUS1 0x0020 /* PCS 10GBASE-R Status 1 */
+ /* other PCS registers exist and can be defined as needed */
+
+/* PHY registers - XS (device 4) */
+#define PHY_XS_CONTROL1 0x0000 /* XS Control 1 */
+#define PHY_XS_STATUS1 0x0001 /* XS Status 1 */
+#define PHY_XS_LANE_STATUS 0x0018 /* XS Lane Status */
+ /* other XS registers exist and can be defined as needed */
+
+/* PHY_PMA_CONTROL1 register bit definitions */
+#define PMA_CONTROL1_RESET 0x8000 /* PMA/PMD reset */
+
+/* PHY_PMA_RCV_DET register bit definitions */
+#define PMA_RCV_DETECT 0x0001 /* PMA/PMD receive signal detect */
+
+/* PHY_PCS_10G_STATUS1 register bit definitions */
+#define PCS_10B_BLOCK_LOCK 0x0001 /* PCS 10GBASE-R locked to receive blocks */
+
+/* PHY_XS_LANE_STATUS register bit definitions */
+#define XS_LANE_ALIGN 0x1000 /* XS transmit lanes aligned */
+
+/* PHY Microcode download data structure */
+struct phy_ucode {
ushort Addr;
ushort Data;
};
+/* Slow Bus Register Definitions */
+
+/* Module 0 registers */
+#define GPIO_L_IN 0x15 /* GPIO input (low) */
+#define GPIO_L_OUT 0x16 /* GPIO output (low) */
+#define GPIO_L_DIR 0x17 /* GPIO direction (low) */
+#define GPIO_H_IN 0x19 /* GPIO input (high) */
+#define GPIO_H_OUT 0x1A /* GPIO output (high) */
+#define GPIO_H_DIR 0x1B /* GPIO direction (high) */
+
+/* Definitions for other slow bus registers can be added as needed */
-/*****************************************************************************
+
+/*
* Transmit Sequencer Command Descriptor definitions
- *****************************************************************************/
-
-// This descriptor must be placed in GRAM. The address of this descriptor
-// (along with a couple of control bits) is pushed onto the PxhCmdQ or PxlCmdQ
-// (Proxy high or low command queue). This data is read by the Proxy Sequencer,
-// which pushes it onto the XmtCmdQ, which is (eventually) read by the Transmit
-// Sequencer, causing a packet to be transmitted. Not all fields are valid for
-// all commands - see the Sahara spec for details. Note that this structure is
-// only valid when compiled on a little endian machine.
+ *
+ * This descriptor must be placed in GRAM. The address of this descriptor
+ * (along with a couple of control bits) is pushed onto the PxhCmdQ or PxlCmdQ
+ * (Proxy high or low command queue). This data is read by the Proxy Sequencer,
+ * which pushes it onto the XmtCmdQ, which is (eventually) read by the Transmit
+ * Sequencer, causing a packet to be transmitted. Not all fields are valid for
+ * all commands - see the Sahara spec for details. Note that this structure is
+ * only valid when compiled on a little endian machine.
+ */
#pragma pack(push, 1)
-struct XMT_DESC {
- ushort XmtLen; // word 0, bits [15:0] - transmit length
- unsigned char XmtCtl; // word 0, bits [23:16] - transmit control byte
- unsigned char Cmd; // word 0, bits [31:24] - transmit command plus misc.
- u32 XmtBufId; // word 1, bits [31:0] - transmit buffer ID
- unsigned char TcpStrt; // word 2, bits [7:0] - byte address of TCP header
- unsigned char IpStrt; // word 2, bits [15:8] - byte address of IP header
- ushort IpCkSum; // word 2, bits [31:16] - partial IP checksum
- ushort TcpCkSum; // word 3, bits [15:0] - partial TCP checksum
- ushort Rsvd1; // word 3, bits [31:16] - PAD
- u32 Rsvd2; // word 4, bits [31:0] - PAD
- u32 Rsvd3; // word 5, bits [31:0] - PAD
- u32 Rsvd4; // word 6, bits [31:0] - PAD
- u32 Rsvd5; // word 7, bits [31:0] - PAD
+struct xmt_desc {
+ ushort XmtLen; /* word 0, bits [15:0] - transmit length */
+ /* word 0, bits [23:16] - transmit control byte */
+ unsigned char XmtCtl;
+ /* word 0, bits [31:24] - transmit command plus misc. */
+ unsigned char Cmd;
+ /* word 1, bits [31:0] - transmit buffer ID */
+ u32 XmtBufId;
+ /* word 2, bits [7:0] - byte address of TCP header */
+ unsigned char TcpStrt;
+ /* word 2, bits [15:8] - byte address of IP header */
+ unsigned char IpStrt;
+ /* word 2, bits [31:16] - partial IP checksum */
+ ushort IpCkSum;
+ /* word 3, bits [15:0] - partial TCP checksum */
+ ushort TcpCkSum;
+ ushort Rsvd1; /* word 3, bits [31:16] - PAD */
+ u32 Rsvd2; /* word 4, bits [31:0] - PAD */
+ u32 Rsvd3; /* word 5, bits [31:0] - PAD */
+ u32 Rsvd4; /* word 6, bits [31:0] - PAD */
+ u32 Rsvd5; /* word 7, bits [31:0] - PAD */
};
#pragma pack(pop)
-// XMT_DESC Cmd byte definitions
- // command codes
-#define XMT_DESC_CMD_RAW_SEND 0 // raw send descriptor
-#define XMT_DESC_CMD_CSUM_INSERT 1 // checksum insert descriptor
-#define XMT_DESC_CMD_FORMAT 2 // format descriptor
-#define XMT_DESC_CMD_PRIME 3 // prime descriptor
-#define XMT_DESC_CMD_CODE_SHFT 6 // comand code shift (shift to bits [31:30] in word 0)
- // shifted command codes
-#define XMT_RAW_SEND (XMT_DESC_CMD_RAW_SEND << XMT_DESC_CMD_CODE_SHFT)
-#define XMT_CSUM_INSERT (XMT_DESC_CMD_CSUM_INSERT << XMT_DESC_CMD_CODE_SHFT)
-#define XMT_FORMAT (XMT_DESC_CMD_FORMAT << XMT_DESC_CMD_CODE_SHFT)
-#define XMT_PRIME (XMT_DESC_CMD_PRIME << XMT_DESC_CMD_CODE_SHFT)
-
-// XMT_DESC Control Byte (XmtCtl) definitions
-// NOTE: These bits do not work on Sahara (Rev A)!
-#define XMT_CTL_PAUSE_FRAME 0x80 // current frame is a pause control frame (for statistics)
-#define XMT_CTL_CONTROL_FRAME 0x40 // current frame is a control frame (for statistics)
-#define XMT_CTL_PER_PKT_QUAL 0x20 // per packet qualifier
-#define XMT_CTL_PAD_MODE_NONE 0x00 // do not pad frame
-#define XMT_CTL_PAD_MODE_64 0x08 // pad frame to 64 bytes
-#define XMT_CTL_PAD_MODE_VLAN_68 0x10 // pad frame to 64 bytes, and VLAN frames to 68 bytes
-#define XMT_CTL_PAD_MODE_68 0x18 // pad frame to 68 bytes
-#define XMT_CTL_GEN_FCS 0x04 // generate FCS (CRC) for this frame
-#define XMT_CTL_DELAY_FCS_0 0x00 // do not delay FCS calcution
-#define XMT_CTL_DELAY_FCS_1 0x01 // delay FCS calculation by 1 (4-byte) word
-#define XMT_CTL_DELAY_FCS_2 0x02 // delay FCS calculation by 2 (4-byte) words
-#define XMT_CTL_DELAY_FCS_3 0x03 // delay FCS calculation by 3 (4-byte) words
-
-// XMT_DESC XmtBufId definition
-#define XMT_BUF_ID_SHFT 8 // The Xmt buffer ID is formed by dividing
- // the buffer (DRAM) address by 256 (or << 8)
-
-/*****************************************************************************
- * Receiver Sequencer Definitions
- *****************************************************************************/
-
-// Receive Event Queue (queues 3 - 6) bit definitions
-#define RCV_EVTQ_RBFID_MASK 0x0000FFFF // bit mask for the Receive Buffer ID
-
-// Receive Buffer ID definition
-#define RCV_BUF_ID_SHFT 5 // The Rcv buffer ID is formed by dividing
- // the buffer (DRAM) address by 32 (or << 5)
-
-// Format of the 18 byte Receive Buffer returned by the
-// Receive Sequencer for received packets
+/* struct xmt_desc Cmd byte definitions */
+ /* command codes */
+#define XMT_DESC_CMD_RAW_SEND 0 /* raw send descriptor */
+#define XMT_DESC_CMD_CSUM_INSERT 1 /* checksum insert descriptor */
+#define XMT_DESC_CMD_FORMAT 2 /* format descriptor */
+#define XMT_DESC_CMD_PRIME 3 /* prime descriptor */
+/* comand code shift (shift to bits [31:30] in word 0) */
+#define XMT_DESC_CMD_CODE_SHFT 6
+ /* shifted command codes */
+#define XMT_RAW_SEND (XMT_DESC_CMD_RAW_SEND << XMT_DESC_CMD_CODE_SHFT)
+#define XMT_CSUM_INSERT (XMT_DESC_CMD_CSUM_INSERT << XMT_DESC_CMD_CODE_SHFT)
+#define XMT_FORMAT (XMT_DESC_CMD_FORMAT << XMT_DESC_CMD_CODE_SHFT)
+#define XMT_PRIME (XMT_DESC_CMD_PRIME << XMT_DESC_CMD_CODE_SHFT)
+
+/*
+ * struct xmt_desc Control Byte (XmtCtl) definitions
+ * NOTE: These bits do not work on Sahara (Rev A)!
+ */
+/* current frame is a pause control frame (for statistics) */
+#define XMT_CTL_PAUSE_FRAME 0x80
+/* current frame is a control frame (for statistics) */
+#define XMT_CTL_CONTROL_FRAME 0x40
+#define XMT_CTL_PER_PKT_QUAL 0x20 /* per packet qualifier */
+#define XMT_CTL_PAD_MODE_NONE 0x00 /* do not pad frame */
+#define XMT_CTL_PAD_MODE_64 0x08 /* pad frame to 64 bytes */
+/* pad frame to 64 bytes, and VLAN frames to 68 bytes */
+#define XMT_CTL_PAD_MODE_VLAN_68 0x10
+#define XMT_CTL_PAD_MODE_68 0x18 /* pad frame to 68 bytes */
+/* generate FCS (CRC) for this frame */
+#define XMT_CTL_GEN_FCS 0x04
+#define XMT_CTL_DELAY_FCS_0 0x00 /* do not delay FCS calcution */
+/* delay FCS calculation by 1 (4-byte) word */
+#define XMT_CTL_DELAY_FCS_1 0x01
+/* delay FCS calculation by 2 (4-byte) words */
+#define XMT_CTL_DELAY_FCS_2 0x02
+/* delay FCS calculation by 3 (4-byte) words */
+#define XMT_CTL_DELAY_FCS_3 0x03
+
+/* struct xmt_desc XmtBufId definition */
+/*
+ * The Xmt buffer ID is formed by dividing the buffer (DRAM) address
+ * by 256 (or << 8)
+ */
+
+#define XMT_BUF_ID_SHFT 8
+
+/* Receiver Sequencer Definitions */
+
+/* Receive Event Queue (queues 3 - 6) bit definitions */
+/* bit mask for the Receive Buffer ID */
+#define RCV_EVTQ_RBFID_MASK 0x0000FFFF
+
+/* Receive Buffer ID definition */
+/*
+ * The Rcv buffer ID is formed by dividing the buffer (DRAM) address
+ * by 32 (or << 5)
+ */
+#define RCV_BUF_ID_SHFT 5
+
+/*
+ * Format of the 18 byte Receive Buffer returned by the
+ * Receive Sequencer for received packets
+ */
#pragma pack(push, 1)
-struct RCV_BUF_HDR {
- u32 Status; // Status word from Rcv Seq Parser
- ushort Length; // Rcv packet byte count
+struct rcv_buf_hdr {
+ u32 Status; /* Status word from Rcv Seq Parser */
+ ushort Length; /* Rcv packet byte count */
union {
- ushort TcpCsum; // TCP checksum
+ ushort TcpCsum; /* TCP checksum */
struct {
- unsigned char TcpCsumL; // lower 8 bits of the TCP checksum
- unsigned char LinkHash; // Link hash (multicast frames only)
+ /* lower 8 bits of the TCP checksum */
+ unsigned char TcpCsumL;
+ /* Link hash (multicast frames only) */
+ unsigned char LinkHash;
};
};
- ushort SktHash; // Socket hash
- unsigned char TcpHdrOffset; // TCP header offset into packet
- unsigned char IpHdrOffset; // IP header offset into packet
- u32 TpzHash; // Toeplitz hash
- ushort Reserved; // Reserved
+ ushort SktHash; /* Socket hash */
+ unsigned char TcpHdrOffset; /* TCP header offset into packet */
+ unsigned char IpHdrOffset; /* IP header offset into packet */
+ u32 TpzHash; /* Toeplitz hash */
+ ushort Reserved; /* Reserved */
};
#pragma pack(pop)
-
-/*****************************************************************************
- * Queue definitions
- *****************************************************************************/
+/* Queue definitions */
/* Ingress (read only) queue numbers */
-#define PXY_BUF_Q 0 /* Proxy Buffer Queue */
-#define HST_EVT_Q 1 /* Host Event Queue */
-#define XMT_BUF_Q 2 /* Transmit Buffer Queue */
-#define SKT_EVL_Q 3 /* RcvSqr Socket Event Low Priority Queue */
-#define RCV_EVL_Q 4 /* RcvSqr Rcv Event Low Priority Queue */
-#define SKT_EVH_Q 5 /* RcvSqr Socket Event High Priority Queue */
-#define RCV_EVH_Q 6 /* RcvSqr Rcv Event High Priority Queue */
-#define DMA_RSP_Q 7 /* Dma Response Queue - one per CPU context */
+#define PXY_BUF_Q 0 /* Proxy Buffer Queue */
+#define HST_EVT_Q 1 /* Host Event Queue */
+#define XMT_BUF_Q 2 /* Transmit Buffer Queue */
+#define SKT_EVL_Q 3 /* RcvSqr Socket Event Low Priority Queue */
+#define RCV_EVL_Q 4 /* RcvSqr Rcv Event Low Priority Queue */
+#define SKT_EVH_Q 5 /* RcvSqr Socket Event High Priority Queue */
+#define RCV_EVH_Q 6 /* RcvSqr Rcv Event High Priority Queue */
+#define DMA_RSP_Q 7 /* Dma Response Queue - one per CPU context */
/* Local (read/write) queue numbers */
-#define LOCAL_A_Q 8 /* Spare local Queue */
-#define LOCAL_B_Q 9 /* Spare local Queue */
-#define LOCAL_C_Q 10 /* Spare local Queue */
-#define FSM_EVT_Q 11 /* Finite-State-Machine Event Queue */
-#define SBF_PAL_Q 12 /* System Buffer Physical Address (low) Queue */
-#define SBF_PAH_Q 13 /* System Buffer Physical Address (high) Queue */
-#define SBF_VAL_Q 14 /* System Buffer Virtual Address (low) Queue */
-#define SBF_VAH_Q 15 /* System Buffer Virtual Address (high) Queue */
+#define LOCAL_A_Q 8 /* Spare local Queue */
+#define LOCAL_B_Q 9 /* Spare local Queue */
+#define LOCAL_C_Q 10 /* Spare local Queue */
+#define FSM_EVT_Q 11 /* Finite-State-Machine Event Queue */
+#define SBF_PAL_Q 12 /* System Buffer Physical Address (low) Queue */
+#define SBF_PAH_Q 13 /* System Buffer Physical Address (high) Queue*/
+#define SBF_VAL_Q 14 /* System Buffer Virtual Address (low) Queue */
+#define SBF_VAH_Q 15 /* System Buffer Virtual Address (high) Queue */
/* Egress (write only) queue numbers */
-#define H2G_CMD_Q 16 /* Host to GlbRam DMA Command Queue */
-#define H2D_CMD_Q 17 /* Host to DRAM DMA Command Queue */
-#define G2H_CMD_Q 18 /* GlbRam to Host DMA Command Queue */
-#define G2D_CMD_Q 19 /* GlbRam to DRAM DMA Command Queue */
-#define D2H_CMD_Q 20 /* DRAM to Host DMA Command Queue */
-#define D2G_CMD_Q 21 /* DRAM to GlbRam DMA Command Queue */
-#define D2D_CMD_Q 22 /* DRAM to DRAM DMA Command Queue */
-#define PXL_CMD_Q 23 /* Low Priority Proxy Command Queue */
-#define PXH_CMD_Q 24 /* High Priority Proxy Command Queue */
-#define RSQ_CMD_Q 25 /* Receive Sequencer Command Queue */
-#define RCV_BUF_Q 26 /* Receive Buffer Queue */
+#define H2G_CMD_Q 16 /* Host to GlbRam DMA Command Queue */
+#define H2D_CMD_Q 17 /* Host to DRAM DMA Command Queue */
+#define G2H_CMD_Q 18 /* GlbRam to Host DMA Command Queue */
+#define G2D_CMD_Q 19 /* GlbRam to DRAM DMA Command Queue */
+#define D2H_CMD_Q 20 /* DRAM to Host DMA Command Queue */
+#define D2G_CMD_Q 21 /* DRAM to GlbRam DMA Command Queue */
+#define D2D_CMD_Q 22 /* DRAM to DRAM DMA Command Queue */
+#define PXL_CMD_Q 23 /* Low Priority Proxy Command Queue */
+#define PXH_CMD_Q 24 /* High Priority Proxy Command Queue */
+#define RSQ_CMD_Q 25 /* Receive Sequencer Command Queue */
+#define RCV_BUF_Q 26 /* Receive Buffer Queue */
/* Bit definitions for the Proxy Command queues (PXL_CMD_Q and PXH_CMD_Q) */
-#define PXY_COPY_EN 0x00200000 /* enable copy of xmt descriptor to xmt command queue */
-#define PXY_SIZE_16 0x00000000 /* copy 16 bytes */
-#define PXY_SIZE_32 0x00100000 /* copy 32 bytes */
+/* enable copy of xmt descriptor to xmt command queue */
+#define PXY_COPY_EN 0x00200000
+#define PXY_SIZE_16 0x00000000 /* copy 16 bytes */
+#define PXY_SIZE_32 0x00100000 /* copy 32 bytes */
+
+/* SXG EEPROM/Flash Configuration Definitions */
+
+/* Location of configuration data in EEPROM or Flash */
+/* start addr for config info in EEPROM */
+#define EEPROM_CONFIG_START_ADDR 0x00
+/* start addr for config info in Flash */
+#define FLASH_CONFIG_START_ADDR 0x80
+
+/* Configuration data section defines */
+#define HW_CFG_SECTION_SIZE 512 /* size of H/W section */
+#define HW_CFG_SECTION_SIZE_A 256 /* size of H/W section (Sahara rev A) */
+/* starting location (offset) of S/W section */
+#define SW_CFG_SECTION_START 512
+/* starting location (offset) of S/W section (Sahara rev A) */
+#define SW_CFG_SECTION_START_A 256
+#define SW_CFG_SECTION_SIZE 128 /* size of S/W section */
+/*
+ * H/W configuration data magic word Goes in Addr field of first
+ * struct hw_cfg_data entry
+ */
+#define HW_CFG_MAGIC_WORD 0xA5A5
+/*
+ * H/W configuration data terminator Goes in Addr field of last
+ * struct hw_cfg_data entry
+ */
+#define HW_CFG_TERMINATOR 0xFFFF
-/*****************************************************************************
- * SXG EEPROM/Flash Configuration Definitions
- *****************************************************************************/
-#pragma pack(push, 1)
+#define SW_CFG_MAGIC_WORD 0x5A5A /* S/W configuration data magic word */
-/* */
-struct HW_CFG_DATA {
- ushort Addr;
- union {
- ushort Data;
- ushort Checksum;
- };
+#pragma pack(push, 1)
+/*
+ * Structure for an element of H/W configuration data.
+ * Read by the Sahara hardware
+ */
+struct hw_cfg_data {
+ ushort Addr;
+ ushort Data;
};
-/* */
-#define NUM_HW_CFG_ENTRIES ((128/sizeof(struct HW_CFG_DATA)) - 4)
-
-/* MAC address */
-struct SXG_CONFIG_MAC {
- unsigned char MacAddr[6]; /* MAC Address */
+/*
+ * Number of struct hw_cfg_data structures to put in the configuration data
+ * data structure (struct sxg_config or struct sxg_config_a). The number is
+ * computed to fill the entire H/W config section of the structure.
+ */
+#define NUM_HW_CFG_ENTRIES \
+ (HW_CFG_SECTION_SIZE / sizeof(struct hw_cfg_data))
+#define NUM_HW_CFG_ENTRIES_A \
+ (HW_CFG_SECTION_SIZE_A / sizeof(struct hw_cfg_data))
+
+/* MAC address structure */
+struct sxg_config_mac {
+ unsigned char MacAddr[6]; /* MAC Address */
};
-/* */
-struct ATK_FRU {
+/* FRU data structure */
+struct atk_fru {
unsigned char PartNum[6];
unsigned char Revision[2];
unsigned char Serial[14];
@@ -697,38 +888,121 @@ struct ATK_FRU {
#define EMC_FRU_FORMAT 0x0005
#define NO_FRU_FORMAT 0xFFFF
+#define ATK_OEM_ASSY_SIZE 10 /* assy num is 9 chars plus \0 */
+
+/* OEM FRU structure for Alacritech */
+struct atk_oem {
+ unsigned char Assy[ATK_OEM_ASSY_SIZE];
+};
+
+#define OEM_EEPROM_FRUSIZE 74 /* size of OEM fru info - size */
+/* chosen to fill out the S/W section */
+
+union oem_fru { /* OEM FRU information */
+ unsigned char OemFru[OEM_EEPROM_FRUSIZE];
+ struct atk_oem AtkOem;
+};
+
+/* Structure to hold the S/W configuration data. */
+struct sw_cfg_data {
+ ushort MagicWord; /* Magic word for section 2 */
+ ushort Version; /* Format version */
+ struct sxg_config_mac MacAddr[4]; /* space for 4 MAC addresses */
+ struct atk_fru AtkFru; /* FRU information */
+ ushort OemFruFormat; /* OEM FRU format type */
+ union oem_fru OemFru; /* OEM FRU information */
+ ushort Checksum; /* Checksum of section 2 */
+};
+
+
/* EEPROM/Flash Format */
-struct SXG_CONFIG {
- /* */
- /* Section 1 (128 bytes) */
- /* */
- ushort MagicWord; /* EEPROM/FLASH Magic code 'A5A5' */
- ushort SpiClks; /* SPI bus clock dividers */
- struct HW_CFG_DATA HwCfg[NUM_HW_CFG_ENTRIES];
- /* */
- /* */
- /* */
- ushort Version; /* EEPROM format version */
- struct SXG_CONFIG_MAC MacAddr[4]; /* space for 4 MAC addresses */
- struct ATK_FRU AtkFru; /* FRU information */
- ushort OemFruFormat; /* OEM FRU format type */
- unsigned char OemFru[76]; /* OEM FRU information (optional) */
- ushort Checksum; /* Checksum of section 2 */
- /* CS info XXXTODO */
+struct sxg_config {
+ /* H/W Section - Read by Sahara hardware (512 bytes) */
+ struct hw_cfg_data HwCfg[NUM_HW_CFG_ENTRIES];
+ /* S/W Section - Other configuration data (128 bytes) */
+ struct sw_cfg_data SwCfg;
+};
+
+/* EEPROM/Flash Format (Sahara rev A) */
+struct sxg_config_a {
+ /* H/W Section - Read by Sahara hardware (256 bytes) */
+ struct hw_cfg_data HwCfg[NUM_HW_CFG_ENTRIES_A];
+
+ /* S/W Section - Other configuration data (128 bytes) */
+ struct sw_cfg_data SwCfg;
+};
+
+#ifdef WINDOWS_COMPILER
+/*
+ * The following macro is something of a kludge, but it is the only way
+ * that I could find to catch certain programming errors at compile time.
+ * If the asserted condition is true, then nothing happens. If false, then
+ * the compiler tries to typedef an array with -1 members, which generates
+ * an error. Unfortunately, the error message is meaningless, but at least
+ * it catches the problem. This macro would be unnecessary if the compiler
+ * allowed the sizeof and offsetof macros to be used in the #if directive.
+ */
+#define compile_time_assert(cond) \
+ typedef char comp_error[(cond) ? 1 : -1]
+
+/*
+ * A compiler error on either of the next two lines indicates that the struct sxg_config
+ * structure was built incorrectly. Unfortunately, the error message produced
+ * is meaningless. But this is apparently the only way to catch this problem
+ * at compile time.
+ */
+compile_time_assert (offsetof(struct sxg_config, SwCfg) == SW_CFG_SECTION_START);
+compile_time_assert (sizeof(struct sxg_config) == HW_CFG_SECTION_SIZE
+ + SW_CFG_SECTION_SIZE);
+
+compile_time_assert (offsetof(struct sxg_config_a, SwCfg)
+ == SW_CFG_SECTION_START_A);
+compile_time_assert (sizeof(struct sxg_config_a) == HW_CFG_SECTION_SIZE_A
+ + SW_CFG_SECTION_SIZE);
+#endif
+/*
+ * Structure used to pass information between driver and user-mode
+ * control application
+ */
+struct adapt_userinfo {
+ bool LinkUp;
+ /* use LinkUp - any need for other states? */
+ /* u32 LinkState; */
+ u32 LinkSpeed; /* not currently needed */
+ u32 LinkDuplex; /* not currently needed */
+ u32 Port; /* not currently needed */
+ u32 PhysPort; /* not currently needed */
+ ushort PciLanes;
+ unsigned char MacAddr[6];
+ unsigned char CurrMacAddr[6];
+ struct atk_fru AtkFru;
+ ushort OemFruFormat;
+ union oem_fru OemFru;
};
+
#pragma pack(pop)
-/*****************************************************************************
- * Miscellaneous Hardware definitions
- *****************************************************************************/
+/* Miscellaneous Hardware definitions */
-// Sahara (ASIC level) defines
-#define SAHARA_GRAM_SIZE 0x020000 // GRAM size - 128 KB
-#define SAHARA_DRAM_SIZE 0x200000 // DRAM size - 2 MB
-#define SAHARA_QRAM_SIZE 0x004000 // QRAM size - 16K entries (64 KB)
-#define SAHARA_WCS_SIZE 0x002000 // WCS - 8K instructions (x 108 bits)
+/* Type of ASIC in use */
+enum ASIC_TYPE{
+ SAHARA_REV_A,
+ SAHARA_REV_B
+};
-// Arabia (board level) defines
-#define FLASH_SIZE 0x080000 // 512 KB (4 Mb)
-#define EEPROM_SIZE_XFMR 512 // true EEPROM size (bytes), including xfmr area
-#define EEPROM_SIZE_NO_XFMR 256 // EEPROM size excluding xfmr area
+/* Sahara (ASIC level) defines */
+#define SAHARA_GRAM_SIZE 0x020000 /* GRAM size - 128 KB */
+#define SAHARA_DRAM_SIZE 0x200000 /* DRAM size - 2 MB */
+/* QRAM size - 16K entries (64 KB) */
+#define SAHARA_QRAM_SIZE 0x004000
+/* WCS - 8K instructions (x 108 bits) */
+#define SAHARA_WCS_SIZE 0x002000
+
+/* Arabia (board level) defines */
+#define FLASH_SIZE 0x080000 /* 512 KB (4 Mb) */
+/* EEPROM size (bytes), including xfmr area */
+#define EEPROM_SIZE_XFMR 1024
+/* EEPROM size excluding xfmr area (512 + 128) */
+#define EEPROM_SIZE_NO_XFMR 640
+/* EEPROM size for Sahara rev A */
+#define EEPROM_SIZE_REV_A 512
diff --git a/drivers/staging/sxg/sxgphycode.h b/drivers/staging/sxg/sxgphycode.h
index 167f356ef86b..adfb6744b711 100644
--- a/drivers/staging/sxg/sxgphycode.h
+++ b/drivers/staging/sxg/sxgphycode.h
@@ -1,24 +1,24 @@
-/*
+/********************************************************************
* Copyright (C) 1997-2008 Alacritech, Inc. All rights reserved
*
* sxgphycode.h:
*
* This file PHY microcode and register initialization data.
- */
+ ********************************************************************/
-/**********************************************************************
+/*
* PHY Microcode
*
* The following contains both PHY microcode and PHY register
* initialization data. It is specific to both the PHY and the
* type of transceiver.
- *
- **********************************************************************/
+ */
/*
- * Download for AEL2005C PHY with SR/LR transceiver (10GBASE-SR or 10GBASE-LR)
+ * Download for AEL2005C PHY with SR/LR transceiver
+ * (10GBASE-SR or 10GBASE-LR)
*/
-static struct PHY_UCODE PhyUcode[] = {
+static struct phy_ucode PhyUcode[] = {
/*
* NOTE: An address of 0 is a special case. When the download routine
* sees an address of 0, it does not write to the PHY. Instead, it
diff --git a/drivers/staging/tuxguardian/Kconfig b/drivers/staging/tuxguardian/Kconfig
new file mode 100644
index 000000000000..a34bf37399da
--- /dev/null
+++ b/drivers/staging/tuxguardian/Kconfig
@@ -0,0 +1,8 @@
+config SECURITY_TUXGUARDIAN
+ tristate "TuxGuardian network access control"
+ depends on SECURITY_NETWORK && BROKEN
+ default N
+ ---help---
+ Enable support for TuxGuardian, an access control that
+ attempts to provide control over every process that connects
+ to the network.
diff --git a/drivers/staging/tuxguardian/Makefile b/drivers/staging/tuxguardian/Makefile
new file mode 100644
index 000000000000..85fc34f82571
--- /dev/null
+++ b/drivers/staging/tuxguardian/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_SECURITY_TUXGUARDIAN) += tuxg.o
+
+tuxg-objs := tg-defs.o tg.o
diff --git a/drivers/staging/tuxguardian/capability.c b/drivers/staging/tuxguardian/capability.c
new file mode 100644
index 000000000000..f9b35cc0b248
--- /dev/null
+++ b/drivers/staging/tuxguardian/capability.c
@@ -0,0 +1,102 @@
+/*
+ * Capabilities Linux Security Module
+ *
+ * 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/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/security.h>
+#include <linux/file.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/pagemap.h>
+#include <linux/swap.h>
+#include <linux/smp_lock.h>
+#include <linux/skbuff.h>
+#include <linux/netlink.h>
+#include <linux/ptrace.h>
+#include <linux/moduleparam.h>
+
+static struct security_operations capability_ops = {
+ .ptrace = cap_ptrace,
+ .capget = cap_capget,
+ .capset_check = cap_capset_check,
+ .capset_set = cap_capset_set,
+ .capable = cap_capable,
+ .settime = cap_settime,
+ .netlink_send = cap_netlink_send,
+ .netlink_recv = cap_netlink_recv,
+
+ .bprm_apply_creds = cap_bprm_apply_creds,
+ .bprm_set_security = cap_bprm_set_security,
+ .bprm_secureexec = cap_bprm_secureexec,
+
+ .inode_setxattr = cap_inode_setxattr,
+ .inode_removexattr = cap_inode_removexattr,
+
+ .task_post_setuid = cap_task_post_setuid,
+ .task_reparent_to_init = cap_task_reparent_to_init,
+
+ .syslog = cap_syslog,
+
+ .vm_enough_memory = cap_vm_enough_memory,
+};
+
+/* flag to keep track of how we were registered */
+static int secondary;
+
+static int capability_disable;
+module_param_named(disable, capability_disable, int, 0);
+MODULE_PARM_DESC(disable, "To disable capabilities module set disable = 1");
+
+static int __init capability_init (void)
+{
+ if (capability_disable) {
+ printk(KERN_INFO "Capabilities disabled at initialization\n");
+ return 0;
+ }
+ /* register ourselves with the security framework */
+ if (register_security (&capability_ops)) {
+ /* try registering with primary module */
+ if (mod_reg_security (KBUILD_MODNAME, &capability_ops)) {
+ printk (KERN_INFO "Failure registering capabilities "
+ "with primary security module.\n");
+ return -EINVAL;
+ }
+ secondary = 1;
+ }
+ printk (KERN_INFO "Capability LSM initialized%s\n",
+ secondary ? " as secondary" : "");
+ return 0;
+}
+
+static void __exit capability_exit (void)
+{
+ if (capability_disable)
+ return;
+ /* remove ourselves from the security framework */
+ if (secondary) {
+ if (mod_unreg_security (KBUILD_MODNAME, &capability_ops))
+ printk (KERN_INFO "Failure unregistering capabilities "
+ "with primary module.\n");
+ return;
+ }
+
+ if (unregister_security (&capability_ops)) {
+ printk (KERN_INFO
+ "Failure unregistering capabilities with the kernel\n");
+ }
+}
+
+security_initcall (capability_init);
+module_exit (capability_exit);
+
+MODULE_DESCRIPTION("Standard Linux Capabilities Security Module");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/tuxguardian/commoncap.c b/drivers/staging/tuxguardian/commoncap.c
new file mode 100644
index 000000000000..b37a5bb846c2
--- /dev/null
+++ b/drivers/staging/tuxguardian/commoncap.c
@@ -0,0 +1,346 @@
+/* Common capabilities, needed by capability.o and root_plug.o
+ *
+ * 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/capability.h>
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/security.h>
+#include <linux/file.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/pagemap.h>
+#include <linux/swap.h>
+#include <linux/smp_lock.h>
+#include <linux/skbuff.h>
+#include <linux/netlink.h>
+#include <linux/ptrace.h>
+#include <linux/xattr.h>
+#include <linux/hugetlb.h>
+
+int cap_netlink_send(struct sock *sk, struct sk_buff *skb)
+{
+ NETLINK_CB(skb).eff_cap = current->cap_effective;
+ return 0;
+}
+
+EXPORT_SYMBOL(cap_netlink_send);
+
+int cap_netlink_recv(struct sk_buff *skb)
+{
+ if (!cap_raised(NETLINK_CB(skb).eff_cap, CAP_NET_ADMIN))
+ return -EPERM;
+ return 0;
+}
+
+EXPORT_SYMBOL(cap_netlink_recv);
+
+int cap_capable (struct task_struct *tsk, int cap)
+{
+ /* Derived from include/linux/sched.h:capable. */
+ if (cap_raised(tsk->cap_effective, cap))
+ return 0;
+ return -EPERM;
+}
+
+int cap_settime(struct timespec *ts, struct timezone *tz)
+{
+ if (!capable(CAP_SYS_TIME))
+ return -EPERM;
+ return 0;
+}
+
+int cap_ptrace (struct task_struct *parent, struct task_struct *child)
+{
+ /* Derived from arch/i386/kernel/ptrace.c:sys_ptrace. */
+ if (!cap_issubset (child->cap_permitted, current->cap_permitted) &&
+ !capable(CAP_SYS_PTRACE))
+ return -EPERM;
+ return 0;
+}
+
+int cap_capget (struct task_struct *target, kernel_cap_t *effective,
+ kernel_cap_t *inheritable, kernel_cap_t *permitted)
+{
+ /* Derived from kernel/capability.c:sys_capget. */
+ *effective = cap_t (target->cap_effective);
+ *inheritable = cap_t (target->cap_inheritable);
+ *permitted = cap_t (target->cap_permitted);
+ return 0;
+}
+
+int cap_capset_check (struct task_struct *target, kernel_cap_t *effective,
+ kernel_cap_t *inheritable, kernel_cap_t *permitted)
+{
+ /* Derived from kernel/capability.c:sys_capset. */
+ /* verify restrictions on target's new Inheritable set */
+ if (!cap_issubset (*inheritable,
+ cap_combine (target->cap_inheritable,
+ current->cap_permitted))) {
+ return -EPERM;
+ }
+
+ /* verify restrictions on target's new Permitted set */
+ if (!cap_issubset (*permitted,
+ cap_combine (target->cap_permitted,
+ current->cap_permitted))) {
+ return -EPERM;
+ }
+
+ /* verify the _new_Effective_ is a subset of the _new_Permitted_ */
+ if (!cap_issubset (*effective, *permitted)) {
+ return -EPERM;
+ }
+
+ return 0;
+}
+
+void cap_capset_set (struct task_struct *target, kernel_cap_t *effective,
+ kernel_cap_t *inheritable, kernel_cap_t *permitted)
+{
+ target->cap_effective = *effective;
+ target->cap_inheritable = *inheritable;
+ target->cap_permitted = *permitted;
+}
+
+int cap_bprm_set_security (struct linux_binprm *bprm)
+{
+ /* Copied from fs/exec.c:prepare_binprm. */
+
+ /* We don't have VFS support for capabilities yet */
+ cap_clear (bprm->cap_inheritable);
+ cap_clear (bprm->cap_permitted);
+ cap_clear (bprm->cap_effective);
+
+ /* To support inheritance of root-permissions and suid-root
+ * executables under compatibility mode, we raise all three
+ * capability sets for the file.
+ *
+ * If only the real uid is 0, we only raise the inheritable
+ * and permitted sets of the executable file.
+ */
+
+ if (!issecure (SECURE_NOROOT)) {
+ if (bprm->e_uid == 0 || current->uid == 0) {
+ cap_set_full (bprm->cap_inheritable);
+ cap_set_full (bprm->cap_permitted);
+ }
+ if (bprm->e_uid == 0)
+ cap_set_full (bprm->cap_effective);
+ }
+ return 0;
+}
+
+void cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe)
+{
+ /* Derived from fs/exec.c:compute_creds. */
+ kernel_cap_t new_permitted, working;
+
+ new_permitted = cap_intersect (bprm->cap_permitted, cap_bset);
+ working = cap_intersect (bprm->cap_inheritable,
+ current->cap_inheritable);
+ new_permitted = cap_combine (new_permitted, working);
+
+ if (bprm->e_uid != current->uid || bprm->e_gid != current->gid ||
+ !cap_issubset (new_permitted, current->cap_permitted)) {
+ current->mm->dumpable = suid_dumpable;
+
+ if (unsafe & ~LSM_UNSAFE_PTRACE_CAP) {
+ if (!capable(CAP_SETUID)) {
+ bprm->e_uid = current->uid;
+ bprm->e_gid = current->gid;
+ }
+ if (!capable (CAP_SETPCAP)) {
+ new_permitted = cap_intersect (new_permitted,
+ current->cap_permitted);
+ }
+ }
+ }
+
+ current->suid = current->euid = current->fsuid = bprm->e_uid;
+ current->sgid = current->egid = current->fsgid = bprm->e_gid;
+
+ /* For init, we want to retain the capabilities set
+ * in the init_task struct. Thus we skip the usual
+ * capability rules */
+ if (current->pid != 1) {
+ current->cap_permitted = new_permitted;
+ current->cap_effective =
+ cap_intersect (new_permitted, bprm->cap_effective);
+ }
+
+ /* AUD: Audit candidate if current->cap_effective is set */
+
+ current->keep_capabilities = 0;
+}
+
+int cap_bprm_secureexec (struct linux_binprm *bprm)
+{
+ /* If/when this module is enhanced to incorporate capability
+ bits on files, the test below should be extended to also perform a
+ test between the old and new capability sets. For now,
+ it simply preserves the legacy decision algorithm used by
+ the old userland. */
+ return (current->euid != current->uid ||
+ current->egid != current->gid);
+}
+
+int cap_inode_setxattr(struct dentry *dentry, char *name, void *value,
+ size_t size, int flags)
+{
+ if (!strncmp(name, XATTR_SECURITY_PREFIX,
+ sizeof(XATTR_SECURITY_PREFIX) - 1) &&
+ !capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ return 0;
+}
+
+int cap_inode_removexattr(struct dentry *dentry, char *name)
+{
+ if (!strncmp(name, XATTR_SECURITY_PREFIX,
+ sizeof(XATTR_SECURITY_PREFIX) - 1) &&
+ !capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ return 0;
+}
+
+/* moved from kernel/sys.c. */
+/*
+ * cap_emulate_setxuid() fixes the effective / permitted capabilities of
+ * a process after a call to setuid, setreuid, or setresuid.
+ *
+ * 1) When set*uiding _from_ one of {r,e,s}uid == 0 _to_ all of
+ * {r,e,s}uid != 0, the permitted and effective capabilities are
+ * cleared.
+ *
+ * 2) When set*uiding _from_ euid == 0 _to_ euid != 0, the effective
+ * capabilities of the process are cleared.
+ *
+ * 3) When set*uiding _from_ euid != 0 _to_ euid == 0, the effective
+ * capabilities are set to the permitted capabilities.
+ *
+ * fsuid is handled elsewhere. fsuid == 0 and {r,e,s}uid!= 0 should
+ * never happen.
+ *
+ * -astor
+ *
+ * cevans - New behaviour, Oct '99
+ * A process may, via prctl(), elect to keep its capabilities when it
+ * calls setuid() and switches away from uid==0. Both permitted and
+ * effective sets will be retained.
+ * Without this change, it was impossible for a daemon to drop only some
+ * of its privilege. The call to setuid(!=0) would drop all privileges!
+ * Keeping uid 0 is not an option because uid 0 owns too many vital
+ * files..
+ * Thanks to Olaf Kirch and Peter Benie for spotting this.
+ */
+static inline void cap_emulate_setxuid (int old_ruid, int old_euid,
+ int old_suid)
+{
+ if ((old_ruid == 0 || old_euid == 0 || old_suid == 0) &&
+ (current->uid != 0 && current->euid != 0 && current->suid != 0) &&
+ !current->keep_capabilities) {
+ cap_clear (current->cap_permitted);
+ cap_clear (current->cap_effective);
+ }
+ if (old_euid == 0 && current->euid != 0) {
+ cap_clear (current->cap_effective);
+ }
+ if (old_euid != 0 && current->euid == 0) {
+ current->cap_effective = current->cap_permitted;
+ }
+}
+
+int cap_task_post_setuid (uid_t old_ruid, uid_t old_euid, uid_t old_suid,
+ int flags)
+{
+ switch (flags) {
+ case LSM_SETID_RE:
+ case LSM_SETID_ID:
+ case LSM_SETID_RES:
+ /* Copied from kernel/sys.c:setreuid/setuid/setresuid. */
+ if (!issecure (SECURE_NO_SETUID_FIXUP)) {
+ cap_emulate_setxuid (old_ruid, old_euid, old_suid);
+ }
+ break;
+ case LSM_SETID_FS:
+ {
+ uid_t old_fsuid = old_ruid;
+
+ /* Copied from kernel/sys.c:setfsuid. */
+
+ /*
+ * FIXME - is fsuser used for all CAP_FS_MASK capabilities?
+ * if not, we might be a bit too harsh here.
+ */
+
+ if (!issecure (SECURE_NO_SETUID_FIXUP)) {
+ if (old_fsuid == 0 && current->fsuid != 0) {
+ cap_t (current->cap_effective) &=
+ ~CAP_FS_MASK;
+ }
+ if (old_fsuid != 0 && current->fsuid == 0) {
+ cap_t (current->cap_effective) |=
+ (cap_t (current->cap_permitted) &
+ CAP_FS_MASK);
+ }
+ }
+ break;
+ }
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+void cap_task_reparent_to_init (struct task_struct *p)
+{
+ p->cap_effective = CAP_INIT_EFF_SET;
+ p->cap_inheritable = CAP_INIT_INH_SET;
+ p->cap_permitted = CAP_FULL_SET;
+ p->keep_capabilities = 0;
+ return;
+}
+
+int cap_syslog (int type)
+{
+ if ((type != 3 && type != 10) && !capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ return 0;
+}
+
+int cap_vm_enough_memory(long pages)
+{
+ int cap_sys_admin = 0;
+
+ if (cap_capable(current, CAP_SYS_ADMIN) == 0)
+ cap_sys_admin = 1;
+ return __vm_enough_memory(pages, cap_sys_admin);
+}
+
+EXPORT_SYMBOL(cap_capable);
+EXPORT_SYMBOL(cap_settime);
+EXPORT_SYMBOL(cap_ptrace);
+EXPORT_SYMBOL(cap_capget);
+EXPORT_SYMBOL(cap_capset_check);
+EXPORT_SYMBOL(cap_capset_set);
+EXPORT_SYMBOL(cap_bprm_set_security);
+EXPORT_SYMBOL(cap_bprm_apply_creds);
+EXPORT_SYMBOL(cap_bprm_secureexec);
+EXPORT_SYMBOL(cap_inode_setxattr);
+EXPORT_SYMBOL(cap_inode_removexattr);
+EXPORT_SYMBOL(cap_task_post_setuid);
+EXPORT_SYMBOL(cap_task_reparent_to_init);
+EXPORT_SYMBOL(cap_syslog);
+EXPORT_SYMBOL(cap_vm_enough_memory);
+
+MODULE_DESCRIPTION("Standard Linux Common Capabilities Security Module");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/tuxguardian/errors.h b/drivers/staging/tuxguardian/errors.h
new file mode 100644
index 000000000000..62ef5412dbcb
--- /dev/null
+++ b/drivers/staging/tuxguardian/errors.h
@@ -0,0 +1,135 @@
+#ifndef __HAS_ERRORS_H
+#define __HAS_ERRORS_H
+
+
+#include <linux/errno.h>
+
+
+struct sock_error_to_string
+{
+ int err;
+ char *explain;
+};
+
+
+struct sock_error_to_string error_to_string[] = {
+ { EPERM, "Not owner" },
+ { ENOENT, "No such file" },
+ { ESRCH, "No such process" },
+ { EINTR, "Interrupted system" },
+ { EIO, "I/O error" },
+ { ENXIO, "No such device" },
+ { E2BIG, "Argument list too long" },
+ { ENOEXEC, "Exec format error" },
+ { EBADF, "Bad file number" },
+ { ECHILD, "No children" },
+ { EAGAIN, "No more processes" },
+ { ENOMEM, "Not enough core" },
+ { EACCES, "Permission denied" },
+ { EFAULT, "Bad address" },
+ { ENOTBLK, "Block device required" },
+ { EBUSY, "Mount device busy" },
+ { EEXIST, "File exists" },
+ { EXDEV, "Cross-device link" },
+ { ENODEV, "No such device" },
+ { ENOTDIR, "Not a directory" },
+ { EISDIR, "Is a directory" },
+ { EINVAL, "Invalid argument" },
+ { ENFILE, "File table overflow" },
+ { EMFILE, "Too many open file" },
+ { ENOTTY, "Not a typewriter" },
+ { ETXTBSY, "Text file busy" },
+ { EFBIG, "File too large" },
+ { ENOSPC, "No space left on" },
+ { ESPIPE, "Illegal seek" },
+ { EROFS, "Read-only file system" },
+ { EMLINK, "Too many links" },
+ { EPIPE, "Broken pipe" },
+ { EWOULDBLOCK, "Operation would block" },
+ { EINPROGRESS, "Operation now in progress" },
+ { EALREADY, "Operation already in progress" },
+ { ENOTSOCK, "Socket operation on" },
+ { EDESTADDRREQ, "Destination address required" },
+ { EMSGSIZE, "Message too long" },
+ { EPROTOTYPE, "Protocol wrong type" },
+ { ENOPROTOOPT, "Protocol not available" },
+ { EPROTONOSUPPORT, "Protocol not supported" },
+ { ESOCKTNOSUPPORT, "Socket type not supported" },
+ { EOPNOTSUPP, "Operation not supported" },
+ { EPFNOSUPPORT, "Protocol family not supported" },
+ { EAFNOSUPPORT, "Address family not supported" },
+ { EADDRINUSE, "Address already in use" },
+ { EADDRNOTAVAIL, "Can't assign requested address" },
+ { ENETDOWN, "Network is down" },
+ { ENETUNREACH, "Network is unreachable" },
+ { ENETRESET, "Network dropped connection" },
+ { ECONNABORTED, "Software caused connection" },
+ { ECONNRESET, "Connection reset by peer" },
+ { ENOBUFS, "No buffer space available" },
+ { EISCONN, "Socket is already connected" },
+ { ENOTCONN, "Socket is not connected" },
+ { ESHUTDOWN, "Can't send after shutdown" },
+ { ETOOMANYREFS, "Too many references" },
+ { ETIMEDOUT, "Connection timed out" },
+ { ECONNREFUSED, "Connection refused" },
+ { ELOOP, "Too many levels of nesting" },
+ { ENAMETOOLONG, "File name too long" },
+ { EHOSTDOWN, "Host is down" },
+ { EHOSTUNREACH, "No route to host" },
+ { ENOTEMPTY, "Directory not empty" },
+ { EUSERS, "Too many users" },
+ { EDQUOT, "Disc quota exceeded" },
+ { ESTALE, "Stale NFS file handle" },
+ { EREMOTE, "Too many levels of remote in the path" },
+ { ENOSTR, "Device is not a stream" },
+ { ETIME, "Timer expired" },
+ { ENOSR, "Out of streams resources" },
+ { ENOMSG, "No message" },
+ { EBADMSG, "Trying to read unreadable message" },
+ { EIDRM, "Identifier removed" },
+ { EDEADLK, "Deadlock condition" },
+ { ENOLCK, "No record locks available" },
+ { ENONET, "Machine is not on network" },
+ { ENOLINK, "The link has been severed" },
+ { EADV, "ADVERTISE error" },
+ { ESRMNT, "SRMOUNT error" },
+ { ECOMM, "Communication error" },
+ { EPROTO, "Protocol error" },
+ { EMULTIHOP, "Multihop attempted" },
+ { EDOTDOT, "Cross mount point" },
+ { EREMCHG, "Remote address change" }
+};
+
+
+
+struct sock_proto_to_string
+{
+ int protonumber;
+ char *description;
+};
+
+static struct sock_proto_to_string proto_to_string[] = {
+ { IPPROTO_IP, "Dummy protocol for TCP" },
+ { IPPROTO_ICMP, "Internet Control Message Protocol" },
+ { IPPROTO_IGMP, "Internet Group Management Protocol" },
+ { IPPROTO_IPIP, "IPIP tunnels (older KA9Q tunnels use 94)" },
+ { IPPROTO_TCP, "Transmission Control Protocol" },
+ { IPPROTO_EGP, "Exterior Gateway Protocol" },
+ { IPPROTO_PUP, "PUP protocol" },
+ { IPPROTO_UDP, "User Datagram Protocol" },
+ { IPPROTO_IDP, "XNS IDP protocol" },
+ { IPPROTO_RSVP, "RSVP protocol" },
+ { IPPROTO_GRE, "Cisco GRE tunnels (rfc 1701,1702" },
+ { IPPROTO_IPV6, "IPv6-in-IPv4 tunnelling" },
+ { IPPROTO_ESP, "Encapsulation Security Payload protocol" },
+ { IPPROTO_AH, "Authentication Header protocol" },
+ { IPPROTO_PIM, "Protocol Independent Multicast" },
+ { IPPROTO_COMP, "Compression Header protocol" },
+ { IPPROTO_SCTP, "Stream Control Transport Protocol" },
+ { IPPROTO_RAW, "Raw IP packets" }
+};
+
+
+
+
+#endif
diff --git a/drivers/staging/tuxguardian/tg-defs.c b/drivers/staging/tuxguardian/tg-defs.c
new file mode 100644
index 000000000000..baa59e03dd4f
--- /dev/null
+++ b/drivers/staging/tuxguardian/tg-defs.c
@@ -0,0 +1,406 @@
+/*
+ TuxGuardian is copyright 2004, Bruno Castro da Silva (brunocs@portoweb.com.br)
+ http://tuxguardian.sourceforge.net
+
+ This file is part of TuxGuardian.
+
+ TuxGuardian 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.
+
+ TuxGuardian is distributed in the hope that it will be 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 TuxGuardian; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+
+
+
+#include "tg-defs.h"
+
+
+
+//--------------------------------------------------------------------------------
+char *err_to_str(int err)
+{
+ int i;
+ int error = -err;
+
+ if (error == 0)
+ return "ok";
+
+ for (i = 0; i < ARRAY_SIZE(error_to_string); i++)
+ if (error_to_string[i].err == error)
+ return error_to_string[i].explain;
+
+ return "unknown error";
+}
+//--------------------------------------------------------------------------------
+
+
+
+//--------------------------------------------------------------------------------
+char *proto_to_str(int protonumber)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(proto_to_string); i++)
+ if (proto_to_string[i].protonumber == protonumber)
+ return proto_to_string[i].description;
+
+ return "unknown ip protocol";
+}
+//--------------------------------------------------------------------------------
+
+
+
+
+//--------------------------------------------------------------------------------
+/* void print_string_to_tty(char *str) */
+/* { */
+
+/* struct tty_struct *my_tty; */
+/* my_tty = current->tty; */
+/* if (my_tty != NULL) { */
+/* (*(my_tty->driver)->write)( */
+/* my_tty, // The tty itself */
+/* 0, // We don't take the string from user space */
+/* str, // String */
+/* strlen(str)); // Length */
+/* (*(my_tty->driver)->write)(my_tty, 0, "\015\012", 2); */
+/* } */
+/* } */
+//--------------------------------------------------------------------------------
+
+
+
+
+//--------------------------------------------------------------------------------
+void print_socket_info(int family, int type)
+{
+ switch (family) {
+
+ case PF_LOCAL: // aka PF_UNIX (the old BSD name) and AF_UNIX/AF_LOCAL
+ // sockets for local interprocess communication
+ switch (type) {
+ case SOCK_STREAM: {
+ printk("(local communication) PF_UNIX SOCK_STREAM");
+ return;
+ }
+ case SOCK_DGRAM: {
+ printk("(local communication) PF_UNIX SOCK_DGRAM");
+ return;
+ }
+ }
+
+ case PF_NETLINK: {
+ // netlink is used to transfer information between kernel modules and user space processes
+ printk("(kernel-user communication) PF_NETLINK");
+ return;
+ }
+
+ case PF_PACKET: {
+ // packet interface on device level (used to receive or send raw packets at the device driver)
+ printk("(device level communication) PF_PACKET");
+ return;
+ }
+
+ case PF_KEY: {
+ // IPSEC stuff.. A user process maintains keyring information on databases that are
+ // accessed by sending messages over this socket
+ printk("(keyring db communication - IPSEC) IPSECPF_KEY");
+ return;
+ }
+
+
+ case PF_INET: {
+ // IPv4 communication
+ printk("(IPv4 communication) PF_INET");
+ switch (type) {
+ case SOCK_STREAM:
+ printk(" SOCK_STREAM");
+ case SOCK_DGRAM:
+ printk(" SOCK_DGRAM");
+ case SOCK_RAW:
+ printk(" SOCK_RAW");
+ }
+ return;
+ }
+
+
+ case PF_INET6: {
+ // IPv6 communication
+ printk("(IPv6 communication) PF_INET6");
+ switch (type) {
+ case SOCK_STREAM:
+ printk(" SOCK_STREAM");
+ case SOCK_DGRAM:
+ printk(" SOCK_DGRAM");
+ case SOCK_RAW:
+ printk(" SOCK_RAW");
+ }
+ return;
+ }
+
+ }
+
+}
+//--------------------------------------------------------------------------------
+
+
+
+
+//--------------------------------------------------------------------------------
+int is_internet_socket(int family)
+{
+
+ if ((family == PF_INET) || (family == PF_INET6))
+ return 1;
+ else
+ return 0;
+}
+//--------------------------------------------------------------------------------
+
+
+
+
+
+//--------------------------------------------------------------------------------
+static int create_socket(struct socket **sock)
+{
+
+ int retval;
+ mm_segment_t oldfs; // to save the current userspace segment descriptor
+
+ // this is useful for SMP (shared memory multiprocessor) architectures, but i call it anyway
+ lock_kernel();
+
+ oldfs = get_fs();
+ set_fs(KERNEL_DS);
+
+ // 3rd parameter (protocol) is set to 0 to specify the family's default
+ retval = sock_create(AF_UNIX, SOCK_STREAM, 0, sock);
+ set_fs(oldfs);
+
+ unlock_kernel();
+
+ return retval;
+
+}
+//--------------------------------------------------------------------------------
+
+
+
+
+
+
+//--------------------------------------------------------------------------------
+static int connect_socket(struct socket **sock)
+{
+
+ struct sockaddr_un loc; // unix domain socket address
+ int retval;
+ mm_segment_t oldfs; // to save the current userspace segment descriptor
+
+
+ oldfs = get_fs();
+ set_fs(KERNEL_DS);
+
+ // if close() is called and there are queued msgs, block until msg is sent or timeout
+ (*sock)->sk->sk_lingertime = 1;
+// (*sock)->sk->sk_reuse = 1;
+
+ loc.sun_family = AF_UNIX;
+ strcpy(loc.sun_path, PATH_MODULE);
+ retval = (*sock)->ops->connect(*sock, (struct sockaddr *)&loc, sizeof(loc), 0);
+
+ set_fs(oldfs);
+
+ return retval;
+
+}
+//--------------------------------------------------------------------------------
+
+
+
+
+//--------------------------------------------------------------------------------
+static int send_query_to_daemon (struct socket **sock, struct tg_query *query, pid_t pid)
+{
+
+ struct msghdr msg; // msg is the message that will carry our query to the daemon
+ struct iovec iov;
+ mm_segment_t oldfs; // to save the current userspace segment descriptor
+
+ int retval;
+
+ if ((*sock)==NULL) {
+ printk(KERN_INFO "TuxGuardian: lost communication with the daemon (sock is NULL)\n");
+ printk(KERN_INFO "TuxGuardian: process #%d (%s) will not be allowed to access the internet\n", pid,
+ current->comm);
+ return -1;
+ }
+ else
+ if (! ((*sock)->sk) ) {
+ printk(KERN_INFO "TuxGuardian: lost communication with the daemon (sock->sk is NULL)\n");
+ printk(KERN_INFO "TuxGuardian: process #%d (%s) will not be allowed to access the internet\n", pid,
+ current->comm);
+ return -1;
+ }
+
+
+ msg.msg_name = 0; // optional address
+ msg.msg_namelen = 0;
+
+ msg.msg_iov = &iov; // information about the send (or receive) buffer.
+ msg.msg_iovlen = 1;
+
+ msg.msg_iov->iov_base = (void *) query; // the send buffer
+ msg.msg_iov->iov_len = (__kernel_size_t) tg_query_size;
+
+ msg.msg_control = NULL; // we don't want to transmit access rights
+ msg.msg_controllen = 0;
+
+ msg.msg_flags = MSG_NOSIGNAL; // we don't want a SIGPIPE if the daemon close
+ // the connection
+
+
+ // any system call checks whether the provided buffer is in a valid userspace address.
+ // To avoid weird error, we'll prevent the usual check to fail by making the task's
+ // maximum valid address conform to kernelspace addresses.
+ oldfs = get_fs(); // saves the current userspace segment descriptor
+ set_fs(KERNEL_DS); // sets to the segment descriptor associated to kernelspace
+
+ retval = sock_sendmsg(*sock, &msg, (size_t) tg_query_size);
+ if (retval == 0) {
+ printk(KERN_INFO "TuxGuardian: connection reset by peer (daemon)\n");
+ printk(KERN_INFO "TuxGuardian: process #%d (%s) will not be allowed to access the internet\n", pid,
+ current->comm);
+ return -1;
+ }
+ else
+ if (retval < 0) {
+ printk(KERN_INFO "TuxGuardian: error %d on sending a query to the daemon\n", retval);
+ printk(KERN_INFO "TuxGuardian: process #%d (%s) will not be allowed to access the internet\n", pid,
+ current->comm);
+ return -1;
+ }
+
+ set_fs(oldfs); // restores the userspace segment descriptor
+
+ return 0;
+
+ // this is the correct way of doing it!
+ /* while (nbytes > 0) { */
+ /* msg.msg_iov->iov_base = (void *) buffer + offset; */
+ /* msg.msg_iov->iov_len = nbytes; */
+
+ /* oldfs = get_fs(); */
+ /* set_fs(KERNEL_DS); */
+ /* len = sock_sendmsg(sock, &msg, nbytes); */
+ /* set_fs(oldfs); */
+
+ /* if (len < 0) { */
+ /* ret = -1; */
+ /* break; */
+ /* } */
+
+ /* nbytes -= len; */
+ /* offset += len; */
+ /* } */
+
+}
+//--------------------------------------------------------------------------------
+
+
+
+
+//--------------------------------------------------------------------------------
+int send_question_permit(struct socket **sock, pid_t pid, int question)
+{
+
+ int retval;
+ struct tg_query query; // used to ask the daemon if 'pid' is allowed to use the internet
+
+ retval = create_socket(sock);
+ if (retval != 0) {
+ printk(KERN_INFO "TuxGuardian: communication with daemon failed (could not create a socket)\n");
+ printk(KERN_INFO "TuxGuardian: error %d\n", retval);
+ printk(KERN_INFO "TuxGuardian: process #%d (%s) will not be allowed to access the internet\n", pid,
+ current->comm);
+ return -1;
+ }
+
+ retval = connect_socket(sock);
+ if (retval != 0) {
+ printk(KERN_INFO "TuxGuardian: could not connect to the daemon! Error %d\n", retval);
+ printk(KERN_INFO "TuxGuardian: process #%d (%s) will not be allowed to access the internet\n", pid,
+ current->comm);
+ return -1;
+ }
+
+ query.sender = TG_MODULE;
+ query.seqno = cur_seqno++;
+ query.query_type = question;
+ query.query_data = pid;
+
+ retval = send_query_to_daemon(sock, &query, pid); // (errors are treated inside the function)
+ if (retval != 0)
+ return -1; // don't continue if send_query failed
+
+ // TODO: return query.resposta
+ return retval;
+
+}
+//--------------------------------------------------------------------------------
+
+
+
+
+//--------------------------------------------------------------------------------
+int read_answer_from_daemon(struct socket *sock, struct tg_query *answer)
+{
+
+ struct msghdr msg;
+ struct iovec iov;
+ int retval;
+ mm_segment_t oldfs; // to save the current userspace segment descriptor
+ // struct tg_query answer;
+
+
+ // Receive a packet
+ msg.msg_name = 0;
+ msg.msg_namelen = 0;
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = NULL;
+ msg.msg_controllen = 0;
+ msg.msg_flags = 0;
+
+ msg.msg_iov->iov_base = (void *) answer;
+ msg.msg_iov->iov_len = (__kernel_size_t) tg_query_size;
+
+ oldfs = get_fs();
+ set_fs(KERNEL_DS);
+
+
+ // MSG_PEEK flag: do not remove data from the receive queue
+
+ retval = sock_recvmsg(sock, &msg, (size_t) tg_query_size, MSG_WAITALL /* 0 flags*/);
+ if (retval < 0) {
+ printk(KERN_INFO "TuxGuardian: (%s) read_answer_from_app failed. Error %d (%s)\n",
+ current->comm, retval, err_to_str(retval));
+ }
+
+ set_fs(oldfs);
+
+ return retval;
+
+}
+//--------------------------------------------------------------------------------
diff --git a/drivers/staging/tuxguardian/tg-defs.h b/drivers/staging/tuxguardian/tg-defs.h
new file mode 100644
index 000000000000..9aeeb628311c
--- /dev/null
+++ b/drivers/staging/tuxguardian/tg-defs.h
@@ -0,0 +1,52 @@
+/*
+ TuxGuardian is copyright 2004, Bruno Castro da Silva (brunocs@portoweb.com.br)
+ http://tuxguardian.sourceforge.net
+
+ This file is part of TuxGuardian.
+
+ TuxGuardian 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.
+
+ TuxGuardian is distributed in the hope that it will be 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 TuxGuardian; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+
+
+
+#ifndef __HAS_TG_DEFS_H
+#define __HAS_TG_DEFS_H
+
+
+// #include <linux/tty.h> /* For the tty declarations */
+
+#include "tg.h"
+#include "errors.h"
+
+
+static u32 cur_seqno = 0;
+
+
+// void print_string_to_tty(char *str);
+
+int is_internet_socket(int family);
+void print_socket_info(int family, int type);
+
+int send_question_permit(struct socket **sock, pid_t pid, int question);
+ //int send_question_permit_app(struct socket **sock, pid_t pid);
+int read_answer_from_daemon(struct socket *sock, struct tg_query *answer);
+
+static int create_socket(struct socket **sock);
+static int connect_socket(struct socket **sock);
+static int send_query_to_daemon (struct socket **sock, struct tg_query *query, pid_t pid);
+
+
+#endif
diff --git a/drivers/staging/tuxguardian/tg.c b/drivers/staging/tuxguardian/tg.c
new file mode 100644
index 000000000000..40d4c151a80e
--- /dev/null
+++ b/drivers/staging/tuxguardian/tg.c
@@ -0,0 +1,459 @@
+/*
+ TuxGuardian is copyright 2004, Bruno Castro da Silva (brunocs@portoweb.com.br)
+ http://tuxguardian.sourceforge.net
+
+ This file is part of TuxGuardian.
+
+ TuxGuardian 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.
+
+ TuxGuardian is distributed in the hope that it will be 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 TuxGuardian; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+
+
+
+#include "tg.h"
+#include <linux/ip.h>
+#include <linux/version.h>
+
+#ifndef KERNEL_VERSION
+#define KERNEL_VERSION(a,b,c) (((a) << 16) | ((b) << 8) | (c))
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
+#include <net/inet_sock.h>
+#endif
+
+
+
+int send_question_permit(struct socket **sock, pid_t pid, int question);
+extern int is_internet_socket(int family);
+extern void print_socket_info(int family, int type);
+extern int read_answer_from_daemon(struct socket *sock, struct tg_query *answer);
+
+//--------------------------------------------------------------------------------
+static int tuxguardian_bprm_check_security (struct linux_binprm *bprm)
+{
+/* binprm_security_ops is a set of program loading hook */
+/* debug_message("file %s, e_uid = %d, e_gid = %d\n", */
+/* bprm->filename, bprm->e_uid, bprm->e_gid); */
+ return 0;
+}
+//--------------------------------------------------------------------------------
+
+
+
+//--------------------------------------------------------------------------------
+static int tuxguardian_socket_create(int family, int type, int protocol, int kern)
+{
+ // TODO: i think the 'kern' parameter is used to inform if the socket
+ // was created in kernel space.. not using this parameter, though
+
+ int retval;
+ struct tg_query answer;
+ struct socket *sock;
+
+
+ // local communication is always allowed
+ // (notice that since we are creating local sockets to
+ // communicate w/ userspace this function SHOULD NOT
+ // analyse local sockets or it'll loop)
+
+ if (! is_internet_socket(family)) {
+// printk("local communication always allowed\n");
+ return 0;
+ }
+/* else { */
+/* printk("\nAsking if '%s' may create a socket (", current->comm); */
+/* print_socket_info(family, type); */
+/* printk(")\n"); */
+/* } */
+
+
+ retval = send_question_permit(&sock, current->pid, TG_ASK_PERMIT_APP);
+ if (retval < 0)
+ return -EPERM;
+
+ // TODO: controle de timeout
+ // /usr/src/linux269/fs/ncpfs/sock.c
+ // /usr/src/linux269/net/bluetooth/rfcomm/sock.c
+ // sock_rcvtimeo
+ retval = read_answer_from_daemon(sock, &answer);
+ if (retval < 0)
+ return -EPERM;
+
+
+ switch (answer.query_data) {
+ case YES:
+ return 0;
+ case NO_ACCESS_IS_DENIED:
+ printk(KERN_INFO "TuxGuardian: process #%d (%s) will not be allowed to access the internet"
+ " (ACCESS IS DENIED)\n", current->pid, current->comm);
+ return -EPERM;
+ case NO_WRONG_HASH:
+ printk(KERN_INFO "TuxGuardian: process #%d (%s) will not be allowed to access the internet"
+ " (WRONG MD5HASH)\n", current->pid, current->comm);
+ return -EPERM;
+ case NO_NOT_IN_HASHTABLE:
+ printk(KERN_INFO "TuxGuardian: process #%d (%s) will not be allowed to access the internet"
+ " (APP NOT PERMITTED)\n", current->pid, current->comm);
+ return -EPERM;
+ case NO_ERROR_IN_DAEMON:
+ printk(KERN_INFO "TuxGuardian: process #%d (%s) will not be allowed to access the internet"
+ " (ERR IN DAEMON)\n", current->pid, current->comm);
+ return -EPERM;
+ case NO_USER_FORBID:
+ printk(KERN_INFO "TuxGuardian: process #%d (%s) will not be allowed to access the internet"
+ " (USER FORBID)\n", current->pid, current->comm);
+ return -EPERM;
+ case NO_ERROR_IN_FRONTEND:
+ printk(KERN_INFO "TuxGuardian: process #%d (%s) will not be allowed to access the internet"
+ " (ERR IN FRONTEND)\n", current->pid, current->comm);
+ return -EPERM;
+ default:
+ printk(KERN_INFO "TuxGuardian: process #%d (%s) will not be allowed to access the internet"
+ " (UNKNOWN ANSWER %d)\n", current->pid, current->comm, answer.query_data);
+ return -EPERM;
+ }
+
+
+/* printk("resposta -> sender: %d seqno: %d query_type: %d query_data: %d\n", */
+/* (int)answer.sender, answer.seqno, (int)answer.query_type, answer.query_data); */
+
+ // connection is closed by the daemon
+ // sock_release(sock);
+
+}
+//--------------------------------------------------------------------------------
+
+
+
+
+
+//--------------------------------------------------------------------------------
+static int tuxguardian_socket_connect(struct socket *conn_sock, struct sockaddr *address, int addrlen)
+{
+// printk("tuxguardian_socket_connect!\n");
+ return 0;
+
+}
+//--------------------------------------------------------------------------------
+
+
+//--------------------------------------------------------------------------------
+static int tuxguardian_socket_bind(struct socket *sock, struct sockaddr *address, int addrlen)
+{
+ // printk("tuxguardian_socket_bind!\n");
+ return 0;
+}
+//--------------------------------------------------------------------------------
+
+
+//--------------------------------------------------------------------------------
+static int tuxguardian_socket_listen(struct socket *listen_sock, int backlog)
+{
+ int retval;
+ struct tg_query answer;
+ struct socket *sock;
+
+
+
+
+ // local communication is always allowed
+ // (notice that since we are creating local sockets to
+ // communicate w/ userspace this function SHOULD NOT
+ // analyse local sockets or it'll loop)
+
+ if (! is_internet_socket(listen_sock->sk->sk_family)) {
+// printk("local communication always allowed\n");
+ return 0;
+ }
+/* else { */
+/* printk("\nAsking if '%s' may be a server - ", current->comm); */
+/* print_socket_info(listen_sock->sk->sk_family, listen_sock->sk->sk_type); */
+/* printk("\n protocol %s at port %d\n", listen_sock->sk->sk_prot->name, */
+/* htons(((struct inet_opt *)inet_sk(listen_sock->sk))->sport)); */
+/* } */
+
+ retval = send_question_permit(&sock, current->pid, TG_PERMIT_SERVER);
+ if (retval < 0)
+ return -EPERM;
+
+ // TODO: timeout
+ // /usr/src/linux269/fs/ncpfs/sock.c
+ // /usr/src/linux269/net/bluetooth/rfcomm/sock.c
+ // sock_rcvtimeo
+ retval = read_answer_from_daemon(sock, &answer);
+ if (retval < 0)
+ return -EPERM;
+
+
+ switch (answer.query_data) {
+ case YES:
+ return 0;
+ case NO_ACCESS_IS_DENIED:
+ printk(KERN_INFO "TuxGuardian: process #%d (%s@%d) will not be allowed to act like a server"
+ " (ACCESS IS DENIED)\n", current->pid, current->comm,
+ htons(((struct inet_sock *)inet_sk(listen_sock->sk))->sport));
+ return -EPERM;
+ case NO_WRONG_HASH:
+ printk(KERN_INFO "TuxGuardian: process #%d (%s@%d) will not be allowed to act like a server"
+ " (WRONG MD5HASH)\n", current->pid, current->comm,
+ htons(((struct inet_sock*)inet_sk(listen_sock->sk))->sport));
+ return -EPERM;
+ case NO_NOT_IN_HASHTABLE:
+ printk(KERN_INFO "TuxGuardian: process #%d (%s@%d) will not be allowed to act like a server"
+ " (APP NOT PERMITTED)\n", current->pid, current->comm,
+ htons(((struct inet_sock *)inet_sk(listen_sock->sk))->sport));
+ return -EPERM;
+ case NO_ERROR_IN_DAEMON:
+ printk(KERN_INFO "TuxGuardian: process #%d (%s@%d) will not be allowed to act like a server"
+ " (ERR IN DAEMON)\n", current->pid, current->comm,
+ htons(((struct inet_sock *)inet_sk(listen_sock->sk))->sport));
+ return -EPERM;
+ case NO_USER_FORBID:
+ printk(KERN_INFO "TuxGuardian: process #%d (%s@%d) will not be allowed to act like a server"
+ " (USER FORBID)\n", current->pid, current->comm,
+ htons(((struct inet_sock *)inet_sk(listen_sock->sk))->sport));
+ return -EPERM;
+ case NO_ERROR_IN_FRONTEND:
+ printk(KERN_INFO "TuxGuardian: process #%d (%s@%d) will not be allowed to act like a server"
+ " (ERR IN FRONTEND)\n", current->pid, current->comm,
+ htons(((struct inet_sock *)inet_sk(listen_sock->sk))->sport));
+ return -EPERM;
+ default:
+ printk(KERN_INFO "TuxGuardian: process #%d (%s@%d) will not be allowed to act like a server"
+ " (UNKNOWN ANSWER %d)\n", current->pid, current->comm, answer.query_data,
+ htons(((struct inet_sock *)inet_sk(listen_sock->sk))->sport));
+ return -EPERM;
+ }
+
+
+/* printk("resposta -> sender: %d seqno: %d query_type: %d query_data: %d\n", */
+/* (int)answer.sender, answer.seqno, (int)answer.query_type, answer.query_data); */
+
+ // connection is closed by the daemon
+// sock_release(sock);
+}
+//--------------------------------------------------------------------------------
+
+
+
+//--------------------------------------------------------------------------------
+static int tuxguardian_socket_accept(struct socket *sock, struct socket *newsock)
+{
+// printk("tuxguardian_socket_accept!\n");
+ return 0;
+}
+//--------------------------------------------------------------------------------
+
+
+
+//--------------------------------------------------------------------------------
+static int tuxguardian_socket_sendmsg(struct socket *sock, struct msghdr *msg, int size)
+{
+ // printk("tuxguardian_socket_sendmsg!\n");
+ return 0;
+}
+//--------------------------------------------------------------------------------
+
+
+
+//--------------------------------------------------------------------------------
+static int tuxguardian_socket_recvmsg(struct socket *sock, struct msghdr *msg, int size, int flags)
+{
+ // printk("tuxguardian_socket_recvmsg!\n");
+ return 0;
+}
+//--------------------------------------------------------------------------------
+
+
+
+//--------------------------------------------------------------------------------
+static int tuxguardian_socket_getsockname(struct socket *sock)
+{
+// printk("tuxguardian_socket_getsockname!\n");
+ return 0;
+}
+//--------------------------------------------------------------------------------
+
+
+
+//--------------------------------------------------------------------------------
+static int tuxguardian_socket_getpeername(struct socket *sock)
+{
+// printk("tuxguardian_socket_getpeername!\n");
+ return 0;
+}
+//--------------------------------------------------------------------------------
+
+
+
+//--------------------------------------------------------------------------------
+static int tuxguardian_socket_setsockopt(struct socket *sock,int level,int optname)
+{
+// printk("tuxguardian_socket_setsockopt!\n");
+ return 0;
+}
+//--------------------------------------------------------------------------------
+
+
+
+//--------------------------------------------------------------------------------
+static int tuxguardian_socket_getsockopt(struct socket *sock, int level, int optname)
+{
+// printk("tuxguardian_socket_getsockopt!\n");
+ return 0;
+}
+//--------------------------------------------------------------------------------
+
+
+
+//--------------------------------------------------------------------------------
+static int tuxguardian_socket_shutdown(struct socket *sock, int how)
+{
+// printk("tuxguardian_socket_shutdown!\n");
+ return 0;
+}
+//--------------------------------------------------------------------------------
+
+
+
+//--------------------------------------------------------------------------------
+static int tuxguardian_socket_unix_stream_connect(struct socket *sock,
+ struct socket *other,
+ struct sock *newsk)
+{
+// printk("tuxguardian_socket_unix_stream_connect!\n");
+ return 0;
+}
+//--------------------------------------------------------------------------------
+
+
+
+//--------------------------------------------------------------------------------
+static int tuxguardian_socket_unix_may_send(struct socket *sock,
+ struct socket *other)
+{
+// printk("tuxguardian_socket_unix_stream_send!\n");
+ return 0;
+}
+//--------------------------------------------------------------------------------
+
+
+
+
+
+
+
+
+
+
+// commoncap.c exporta umas coisa dessas
+static struct security_operations tuxguardian_security_ops = {
+ /* Use the capability functions for some of the hooks */
+ .ptrace = cap_ptrace,
+ .capget = cap_capget,
+ .capset_check = cap_capset_check,
+ .capset_set = cap_capset_set,
+ .capable = cap_capable,
+
+ // evil callback that keeps changing name beetwen kernel releases!
+ .bprm_apply_creds = cap_bprm_apply_creds,
+
+ .bprm_set_security = cap_bprm_set_security,
+
+ .task_post_setuid = cap_task_post_setuid,
+ .task_reparent_to_init = cap_task_reparent_to_init,
+
+ .bprm_check_security = tuxguardian_bprm_check_security,
+
+ .socket_create = tuxguardian_socket_create,
+ .socket_connect = tuxguardian_socket_connect,
+
+
+ .socket_bind = tuxguardian_socket_bind,
+ .socket_listen = tuxguardian_socket_listen,
+ .socket_accept = tuxguardian_socket_accept,
+ .socket_sendmsg = tuxguardian_socket_sendmsg,
+ .socket_recvmsg = tuxguardian_socket_recvmsg,
+ .socket_getsockname = tuxguardian_socket_getsockname,
+ .socket_getpeername = tuxguardian_socket_getpeername,
+ .socket_getsockopt = tuxguardian_socket_getsockopt,
+ .socket_setsockopt = tuxguardian_socket_setsockopt,
+ .socket_shutdown = tuxguardian_socket_shutdown,
+ .unix_stream_connect = tuxguardian_socket_unix_stream_connect,
+ .unix_may_send = tuxguardian_socket_unix_may_send,
+
+
+
+};
+
+
+
+
+static int __init tuxguardian_init (void)
+{
+
+ /* register ourselves with the security framework */
+ if (register_security (&tuxguardian_security_ops)) {
+
+ printk(KERN_INFO "Failure registering TuxGuardian module with the kernel\n");
+
+ /* try registering as the primary module */
+ if (mod_reg_security (MY_NAME, &tuxguardian_security_ops)) {
+ printk(KERN_INFO "Failure registering TuxGuardian as the primary security module\n");
+ return -EINVAL;
+ }
+ }
+
+ printk (KERN_INFO "TuxGuardian initialized\n");
+ return 0;
+}
+
+
+
+static void __exit tuxguardian_exit (void)
+{
+
+ /* remove ourselves from the security framework */
+ if (unregister_security (&tuxguardian_security_ops)) {
+ printk (KERN_INFO "Failure unregistering TuxGuardian\n");
+ }
+ else
+ printk (KERN_INFO "\nTuxGuardian module removed\n");
+
+
+}
+
+security_initcall (tuxguardian_init);
+module_exit (tuxguardian_exit);
+
+
+/* MODULE_PARAM(int_param, "i") */
+/* then passing value into module as */
+/* insmod module int_param=x */
+
+/* Initialize the module - show the parameters */
+/* int init_module() */
+/* { */
+/* if (str1 == NULL || str2 == NULL) { */
+/* printk("Next time, do insmod param str1=<something>"); */
+/* printk("str2=<something>\n"); */
+/* } else */
+/* printk("Strings:%s and %s\n", str1, str2); */
+
+MODULE_AUTHOR("Bruno Castro da Silva");
+MODULE_DESCRIPTION("TuxGuardian Security Module");
+// thanks stallman, thanks linus
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/tuxguardian/tg.h b/drivers/staging/tuxguardian/tg.h
new file mode 100644
index 000000000000..683fd4ccddc1
--- /dev/null
+++ b/drivers/staging/tuxguardian/tg.h
@@ -0,0 +1,110 @@
+/*
+ TuxGuardian is copyright 2004, Bruno Castro da Silva (brunocs@portoweb.com.br)
+ http://tuxguardian.sourceforge.net
+
+ This file is part of TuxGuardian.
+
+ TuxGuardian 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.
+
+ TuxGuardian is distributed in the hope that it will be 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 TuxGuardian; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+
+
+#ifndef __HAS_TG_H
+#define __HAS_TG_H
+
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <linux/types.h>
+#include <linux/ctype.h>
+
+#include <linux/sched.h>
+#include <linux/smp_lock.h>
+#include <linux/fs.h>
+#include <asm/unistd.h>
+#include <linux/unistd.h>
+#include <linux/slab.h>
+#include <linux/in.h>
+#include <linux/un.h>
+#include <linux/net.h>
+#include <linux/inet.h>
+#include <linux/skbuff.h>
+#include <net/sock.h>
+#include <linux/poll.h>
+#include <linux/file.h>
+
+
+
+#include <linux/string.h>
+
+#include <linux/security.h> // LSM stuff
+
+
+#define PATH_MODULE "/tmp/tux_daemon_server"
+
+
+#if defined(CONFIG_SECURITY_TESTE_MODULE)
+#define MY_NAME THIS_MODULE->name
+#else
+#define MY_NAME "TuxGuardian"
+#endif
+
+
+// sender
+#define TG_MODULE 0
+#define TG_DAEMON 1
+#define TG_FRONTEND 2
+
+// query_type
+#define TG_ASK_PERMIT_APP 0
+#define TG_RESPOND_PERMIT_APP 1
+#define TG_PERMIT_REMOVE_MODULE 2
+#define TG_PERMIT_ACCESS_FILE 3
+#define TG_PERMIT_SERVER 4
+#define TG_RESPOND_PERMIT_SERVER 5
+
+// RESPOND_PERMIT_APP possibilities
+#define YES 0
+#define YES_SAVE_IN_FILE 6
+#define NO_ACCESS_IS_DENIED 7
+#define NO_SAVE_IN_FILE 8
+#define NO_WRONG_HASH 1
+#define NO_NOT_IN_HASHTABLE 2
+#define NO_ERROR_IN_DAEMON 3
+#define NO_USER_FORBID 4
+#define NO_ERROR_IN_FRONTEND 5
+
+#define debug_message(fmt, arg...) \
+ do { \
+ printk(KERN_INFO "%s: %s: " fmt , \
+ MY_NAME , __FUNCTION__ , \
+ ## arg); \
+ } while (0)
+
+struct tg_query {
+ u8 sender;
+ u32 seqno; // sequence number
+ u8 query_type;
+ u32 query_data; // might be a pid, YES, NO,.. depending on the query_type
+};
+
+#define tg_query_size sizeof(struct tg_query)
+
+
+
+
+#endif
diff --git a/include/linux/connector.h b/include/linux/connector.h
index 34f2789d9b9b..b8fe3c3930b4 100644
--- a/include/linux/connector.h
+++ b/include/linux/connector.h
@@ -39,8 +39,10 @@
#define CN_IDX_V86D 0x4
#define CN_VAL_V86D_UVESAFB 0x1
#define CN_IDX_BB 0x5 /* BlackBoard, from the TSP GPL sampling framework */
+#define CN_DST_IDX 0x6
+#define CN_DST_VAL 0x1
-#define CN_NETLINK_USERS 6
+#define CN_NETLINK_USERS 7
/*
* Maximum connector's message size.
diff --git a/include/linux/dst.h b/include/linux/dst.h
new file mode 100644
index 000000000000..e26fed84b1aa
--- /dev/null
+++ b/include/linux/dst.h
@@ -0,0 +1,587 @@
+/*
+ * 2007+ Copyright (c) Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ * 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.
+ */
+
+#ifndef __DST_H
+#define __DST_H
+
+#include <linux/types.h>
+#include <linux/connector.h>
+
+#define DST_NAMELEN 32
+#define DST_NAME "dst"
+
+enum {
+ /* Remove node with given id from storage */
+ DST_DEL_NODE = 0,
+ /* Add remote node with given id to the storage */
+ DST_ADD_REMOTE,
+ /* Add local node with given id to the storage to be exported and used by remote peers */
+ DST_ADD_EXPORT,
+ /* Crypto initialization command (hash/cipher used to protect the connection) */
+ DST_CRYPTO,
+ /* Security attributes for given connection (permissions for example) */
+ DST_SECURITY,
+ /* Register given node in the block layer subsystem */
+ DST_START,
+ DST_CMD_MAX
+};
+
+struct dst_ctl
+{
+ /* Storage name */
+ char name[DST_NAMELEN];
+ /* Command flags */
+ __u32 flags;
+ /* Command itself (see above) */
+ __u32 cmd;
+ /* Maximum number of pages per single request in this device */
+ __u32 max_pages;
+ /* Stale/error transaction scanning timeout in milliseconds */
+ __u32 trans_scan_timeout;
+ /* Maximum number of retry sends before completing transaction as broken */
+ __u32 trans_max_retries;
+ /* Storage size */
+ __u64 size;
+};
+
+/* Reply command carries completion status */
+struct dst_ctl_ack
+{
+ struct cn_msg msg;
+ int error;
+ int unused[3];
+};
+
+/*
+ * Unfortunaltely socket address structure is not exported to userspace
+ * and is redefined there.
+ */
+#define SADDR_MAX_DATA 128
+
+struct saddr {
+ /* address family, AF_xxx */
+ unsigned short sa_family;
+ /* 14 bytes of protocol address */
+ char sa_data[SADDR_MAX_DATA];
+ /* Number of bytes used in sa_data */
+ unsigned short sa_data_len;
+};
+
+/* Address structure */
+struct dst_network_ctl
+{
+ /* Socket type: datagram, stream...*/
+ unsigned int type;
+ /* Let me guess, is it a Jupiter diameter? */
+ unsigned int proto;
+ /* Peer's address */
+ struct saddr addr;
+};
+
+struct dst_crypto_ctl
+{
+ /* Cipher and hash names */
+ char cipher_algo[DST_NAMELEN];
+ char hash_algo[DST_NAMELEN];
+
+ /* Key sizes. Can be zero for digest for example */
+ unsigned int cipher_keysize, hash_keysize;
+ /* Alignment. Calculated by the DST itself. */
+ unsigned int crypto_attached_size;
+ /* Number of threads to perform crypto operations */
+ int thread_num;
+};
+
+/* Export security attributes have this bits checked in when client connects */
+#define DST_PERM_READ (1<<0)
+#define DST_PERM_WRITE (1<<1)
+
+/*
+ * Right now it is simple model, where each remote address
+ * is assigned to set of permissions it is allowed to perform.
+ * In real world block device does not know anything but
+ * reading and writing, so it should be more than enough.
+ */
+struct dst_secure_user
+{
+ unsigned int permissions;
+ struct saddr addr;
+};
+
+/*
+ * Export control command: device to export and network address to accept
+ * clients to work with given device
+ */
+struct dst_export_ctl
+{
+ char device[DST_NAMELEN];
+ struct dst_network_ctl ctl;
+};
+
+enum {
+ DST_CFG = 1, /* Request remote configuration */
+ DST_IO, /* IO command */
+ DST_IO_RESPONSE, /* IO response */
+ DST_PING, /* Keepalive message */
+ DST_NCMD_MAX,
+};
+
+struct dst_cmd
+{
+ /* Network command itself, see above */
+ __u32 cmd;
+ /*
+ * Size of the attached data
+ * (in most cases, for READ command it means how many bytes were requested)
+ */
+ __u32 size;
+ /* Crypto size: number of attached bytes with digest/hmac */
+ __u32 csize;
+ /* Here we can carry secret data */
+ __u32 reserved;
+ /* Read/write bits, see how they are encoded in bio structure */
+ __u64 rw;
+ /* BIO flags */
+ __u64 flags;
+ /* Unique command id (like transaction ID) */
+ __u64 id;
+ /* Sector to start IO from */
+ __u64 sector;
+ /* Hash data is placed after this header */
+ __u8 hash[0];
+};
+
+/*
+ * Convert command to/from network byte order.
+ * We do not use hton*() functions, since there is
+ * no 64-bit implementation.
+ */
+static inline void dst_convert_cmd(struct dst_cmd *c)
+{
+ c->cmd = __cpu_to_be32(c->cmd);
+ c->csize = __cpu_to_be32(c->csize);
+ c->size = __cpu_to_be32(c->size);
+ c->sector = __cpu_to_be64(c->sector);
+ c->id = __cpu_to_be64(c->id);
+ c->flags = __cpu_to_be64(c->flags);
+ c->rw = __cpu_to_be64(c->rw);
+}
+
+/* Transaction id */
+typedef __u64 dst_gen_t;
+
+#ifdef __KERNEL__
+
+#include <linux/blkdev.h>
+#include <linux/bio.h>
+#include <linux/device.h>
+#include <linux/mempool.h>
+#include <linux/net.h>
+#include <linux/poll.h>
+#include <linux/rbtree.h>
+
+#ifdef CONFIG_DST_DEBUG
+#define dprintk(f, a...) printk(KERN_NOTICE f, ##a)
+#else
+static inline void __attribute__ ((format (printf, 1, 2)))
+ dprintk(const char *fmt, ...) {}
+#endif
+
+struct dst_node;
+
+struct dst_trans
+{
+ /* DST node we are working with */
+ struct dst_node *n;
+
+ /* Entry inside transaction tree */
+ struct rb_node trans_entry;
+
+ /* Merlin kills this transaction when this memory cell equals zero */
+ atomic_t refcnt;
+
+ /* How this transaction should be processed by crypto engine */
+ short enc;
+ /* How many times this transaction was resent */
+ short retries;
+ /* Completion status */
+ int error;
+
+ /* When did we send it to the remote peer */
+ long send_time;
+
+ /* My name is...
+ * Well, computers does not speak, they have unique id instead */
+ dst_gen_t gen;
+
+ /* Block IO we are working with */
+ struct bio *bio;
+
+ /* Network command for above block IO request */
+ struct dst_cmd cmd;
+};
+
+struct dst_crypto_engine
+{
+ /* What should we do with all block requests */
+ struct crypto_hash *hash;
+ struct crypto_ablkcipher *cipher;
+
+ /* Pool of pages used to encrypt data into before sending */
+ int page_num;
+ struct page **pages;
+
+ /* What to do with current request */
+ int enc;
+ /* Who we are and where do we go */
+ struct scatterlist *src, *dst;
+
+ /* Maximum timeout waiting for encryption to be completed */
+ long timeout;
+ /* IV is a 64-bit sequential counter */
+ u64 iv;
+
+ /* Secret data */
+ void *private;
+
+ /* Cached temporary data lives here */
+ int size;
+ void *data;
+};
+
+struct dst_state
+{
+ /* The main state protection */
+ struct mutex state_lock;
+
+ /* Polling machinery for sockets */
+ wait_queue_t wait;
+ wait_queue_head_t *whead;
+ /* Most of events are being waited here */
+ wait_queue_head_t thread_wait;
+
+ /* Who owns this? */
+ struct dst_node *node;
+
+ /* Network address for this state */
+ struct dst_network_ctl ctl;
+
+ /* Permissions to work with: read-only or rw connection */
+ u32 permissions;
+
+ /* Called when we need to clean private data */
+ void (* cleanup)(struct dst_state *st);
+
+ /* Used by the server: BIO completion queues BIOs here */
+ struct list_head request_list;
+ spinlock_t request_lock;
+
+ /* Guess what? No, it is not number of planets */
+ atomic_t refcnt;
+
+ /* This flags is set when connection should be dropped */
+ int need_exit;
+
+ /*
+ * Socket to work with. Second pointer is used for
+ * lockless check if socket was changed before performing
+ * next action (like working with cached polling result)
+ */
+ struct socket *socket, *read_socket;
+
+ /* Cached preallocated data */
+ void *data;
+ unsigned int size;
+
+ /* Currently processed command */
+ struct dst_cmd cmd;
+};
+
+struct dst_info
+{
+ /* Device size */
+ u64 size;
+
+ /* Local device name for export devices */
+ char local[DST_NAMELEN];
+
+ /* Network setup */
+ struct dst_network_ctl net;
+
+ /* Sysfs bits use this */
+ struct device device;
+};
+
+struct dst_node
+{
+ struct list_head node_entry;
+
+ /* Hi, my name is stored here */
+ char name[DST_NAMELEN];
+ /* My cache name is stored here */
+ char cache_name[DST_NAMELEN];
+
+ /* Block device attached to given node.
+ * Only valid for exporting nodes */
+ struct block_device *bdev;
+ /* Network state machine for given peer */
+ struct dst_state *state;
+
+ /* Block IO machinery */
+ struct request_queue *queue;
+ struct gendisk *disk;
+
+ /* Number of threads in processing pool */
+ int thread_num;
+ /* Maximum number of pages in single IO */
+ int max_pages;
+
+ /* I'm that big in bytes */
+ loff_t size;
+
+ /* Exported to userspace node information */
+ struct dst_info *info;
+
+ /*
+ * Security attribute list.
+ * Used only by exporting node currently.
+ */
+ struct list_head security_list;
+ struct mutex security_lock;
+
+ /*
+ * When this unerflows below zero, university collapses.
+ * But this will not happen, since node will be freed,
+ * when reference counter reaches zero.
+ */
+ atomic_t refcnt;
+
+ /* How precisely should I be started? */
+ int (*start)(struct dst_node *);
+
+ /* Crypto capabilities */
+ struct dst_crypto_ctl crypto;
+ u8 *hash_key;
+ u8 *cipher_key;
+
+ /* Pool of processing thread */
+ struct thread_pool *pool;
+
+ /* Transaction IDs live here */
+ atomic_long_t gen;
+
+ /*
+ * How frequently and how many times transaction
+ * tree should be scanned to drop stale objects.
+ */
+ long trans_scan_timeout;
+ int trans_max_retries;
+
+ /* Small gnomes live here */
+ struct rb_root trans_root;
+ struct mutex trans_lock;
+
+ /*
+ * Transaction cache/memory pool.
+ * It is big enough to contain not only transaction
+ * itself, but additional crypto data (digest/hmac).
+ */
+ struct kmem_cache *trans_cache;
+ mempool_t *trans_pool;
+
+ /* This entity scans transaction tree */
+ struct delayed_work trans_work;
+
+ wait_queue_head_t wait;
+};
+
+/* Kernel representation of the security attribute */
+struct dst_secure
+{
+ struct list_head sec_entry;
+ struct dst_secure_user sec;
+};
+
+int dst_process_bio(struct dst_node *n, struct bio *bio);
+
+int dst_node_init_connected(struct dst_node *n, struct dst_network_ctl *r);
+int dst_node_init_listened(struct dst_node *n, struct dst_export_ctl *le);
+
+static inline struct dst_state *dst_state_get(struct dst_state *st)
+{
+ BUG_ON(atomic_read(&st->refcnt) == 0);
+ atomic_inc(&st->refcnt);
+ return st;
+}
+
+void dst_state_put(struct dst_state *st);
+
+struct dst_state *dst_state_alloc(struct dst_node *n);
+int dst_state_socket_create(struct dst_state *st);
+void dst_state_socket_release(struct dst_state *st);
+
+void dst_state_exit_connected(struct dst_state *st);
+
+int dst_state_schedule_receiver(struct dst_state *st);
+
+void dst_dump_addr(struct socket *sk, struct sockaddr *sa, char *str);
+
+static inline void dst_state_lock(struct dst_state *st)
+{
+ mutex_lock(&st->state_lock);
+}
+
+static inline void dst_state_unlock(struct dst_state *st)
+{
+ mutex_unlock(&st->state_lock);
+}
+
+void dst_poll_exit(struct dst_state *st);
+int dst_poll_init(struct dst_state *st);
+
+static inline unsigned int dst_state_poll(struct dst_state *st)
+{
+ unsigned int revents = POLLHUP | POLLERR;
+
+ dst_state_lock(st);
+ if (st->socket)
+ revents = st->socket->ops->poll(NULL, st->socket, NULL);
+ dst_state_unlock(st);
+
+ return revents;
+}
+
+static inline int dst_thread_setup(void *private, void *data)
+{
+ return 0;
+}
+
+void dst_node_put(struct dst_node *n);
+
+static inline struct dst_node *dst_node_get(struct dst_node *n)
+{
+ atomic_inc(&n->refcnt);
+ return n;
+}
+
+int dst_data_recv(struct dst_state *st, void *data, unsigned int size);
+int dst_recv_cdata(struct dst_state *st, void *cdata);
+int dst_data_send_header(struct socket *sock,
+ void *data, unsigned int size, int more);
+
+int dst_send_bio(struct dst_state *st, struct dst_cmd *cmd, struct bio *bio);
+
+int dst_process_io(struct dst_state *st);
+int dst_export_crypto(struct dst_node *n, struct bio *bio);
+int dst_export_send_bio(struct bio *bio);
+int dst_start_export(struct dst_node *n);
+
+int __init dst_export_init(void);
+void dst_export_exit(void);
+
+/* Private structure for export block IO requests */
+struct dst_export_priv
+{
+ struct list_head request_entry;
+ struct dst_state *state;
+ struct bio *bio;
+ struct dst_cmd cmd;
+};
+
+static inline void dst_trans_get(struct dst_trans *t)
+{
+ atomic_inc(&t->refcnt);
+}
+
+struct dst_trans *dst_trans_search(struct dst_node *node, dst_gen_t gen);
+int dst_trans_remove(struct dst_trans *t);
+int dst_trans_remove_nolock(struct dst_trans *t);
+void dst_trans_put(struct dst_trans *t);
+
+/*
+ * Convert bio into network command.
+ */
+static inline void dst_bio_to_cmd(struct bio *bio, struct dst_cmd *cmd,
+ u32 command, u64 id)
+{
+ cmd->cmd = command;
+ cmd->flags = (bio->bi_flags << BIO_POOL_BITS) >> BIO_POOL_BITS;
+ cmd->rw = bio->bi_rw;
+ cmd->size = bio->bi_size;
+ cmd->csize = 0;
+ cmd->id = id;
+ cmd->sector = bio->bi_sector;
+};
+
+int dst_trans_send(struct dst_trans *t);
+int dst_trans_crypto(struct dst_trans *t);
+
+int dst_node_crypto_init(struct dst_node *n, struct dst_crypto_ctl *ctl);
+void dst_node_crypto_exit(struct dst_node *n);
+
+static inline int dst_need_crypto(struct dst_node *n)
+{
+ struct dst_crypto_ctl *c = &n->crypto;
+ /*
+ * Logical OR is appropriate here, but boolean one produces
+ * more optimal code, so it is used instead.
+ */
+ return (c->hash_algo[0] | c->cipher_algo[0]);
+}
+
+int dst_node_trans_init(struct dst_node *n, unsigned int size);
+void dst_node_trans_exit(struct dst_node *n);
+
+/*
+ * Pool of threads.
+ * Ready list contains threads currently free to be used,
+ * active one contains threads with some work scheduled for them.
+ * Caller can wait in given queue when thread is ready.
+ */
+struct thread_pool
+{
+ int thread_num;
+ struct mutex thread_lock;
+ struct list_head ready_list, active_list;
+
+ wait_queue_head_t wait;
+};
+
+void thread_pool_del_worker(struct thread_pool *p);
+void thread_pool_del_worker_id(struct thread_pool *p, unsigned int id);
+int thread_pool_add_worker(struct thread_pool *p,
+ char *name,
+ unsigned int id,
+ void *(* init)(void *data),
+ void (* cleanup)(void *data),
+ void *data);
+
+void thread_pool_destroy(struct thread_pool *p);
+struct thread_pool *thread_pool_create(int num, char *name,
+ void *(* init)(void *data),
+ void (* cleanup)(void *data),
+ void *data);
+
+int thread_pool_schedule(struct thread_pool *p,
+ int (* setup)(void *stored_private, void *setup_data),
+ int (* action)(void *stored_private, void *setup_data),
+ void *setup_data, long timeout);
+int thread_pool_schedule_private(struct thread_pool *p,
+ int (* setup)(void *private, void *data),
+ int (* action)(void *private, void *data),
+ void *data, long timeout, void *id);
+
+#endif /* __KERNEL__ */
+#endif /* __DST_H */