From 3763da2cc535cb34897819a1337f7abf4a60bf22 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 19 Jun 2006 19:59:53 +0000 Subject: [PATCH] remove the wl.o build from the kernel patch and move the driver along with wl, nas and wlc into packages/broadcom-wl SVN-Revision: 4009 --- openwrt/package/broadcom-wl/Makefile | 96 + openwrt/package/broadcom-wl/src/kmod/Makefile | 32 + openwrt/package/broadcom-wl/src/kmod/bcmip.h | 101 + .../package/broadcom-wl/src/kmod/bcmutils.c | 857 +++++ openwrt/package/broadcom-wl/src/kmod/hnddma.c | 1157 ++++++ openwrt/package/broadcom-wl/src/kmod/hnddma.h | 156 + .../package/broadcom-wl/src/kmod/linux_osl.c | 269 ++ .../package/broadcom-wl/src/kmod/linux_osl.h | 171 + .../broadcom-wl/src/kmod/patchtable.pl | 54 + openwrt/package/broadcom-wl/src/kmod/pktq.h | 97 + .../package/broadcom-wl/src/kmod/sbhnddma.h | 284 ++ .../{wlc/src => broadcom-wl/src/wlc}/Makefile | 0 .../src/wlc}/include/bcmdefs.h | 0 .../src/wlc}/include/bcmutils.h | 0 .../src/wlc}/include/proto/802.11.h | 0 .../src/wlc}/include/proto/bcmeth.h | 0 .../src/wlc}/include/proto/bcmevent.h | 0 .../src/wlc}/include/proto/ethernet.h | 0 .../src/wlc}/include/proto/wpa.h | 0 .../src/wlc}/include/typedefs.h | 0 .../src/wlc}/include/wlioctl.h | 0 .../src/wlc}/include/wlutils.h | 0 .../{wlc/src => broadcom-wl/src/wlc}/ioctl.c | 0 .../{wlc/src => broadcom-wl/src/wlc}/wlc.c | 0 openwrt/package/wlc/Makefile | 40 - openwrt/target/linux/brcm-2.4/Config.in | 8 - openwrt/target/linux/brcm-2.4/Makefile | 39 - openwrt/target/linux/brcm-2.4/config | 3 - .../linux/brcm-2.4/patches/001-bcm47xx.patch | 3252 +---------------- 29 files changed, 3275 insertions(+), 3341 deletions(-) create mode 100644 openwrt/package/broadcom-wl/Makefile create mode 100644 openwrt/package/broadcom-wl/src/kmod/Makefile create mode 100644 openwrt/package/broadcom-wl/src/kmod/bcmip.h create mode 100644 openwrt/package/broadcom-wl/src/kmod/bcmutils.c create mode 100644 openwrt/package/broadcom-wl/src/kmod/hnddma.c create mode 100644 openwrt/package/broadcom-wl/src/kmod/hnddma.h create mode 100644 openwrt/package/broadcom-wl/src/kmod/linux_osl.c create mode 100644 openwrt/package/broadcom-wl/src/kmod/linux_osl.h create mode 100644 openwrt/package/broadcom-wl/src/kmod/patchtable.pl create mode 100644 openwrt/package/broadcom-wl/src/kmod/pktq.h create mode 100644 openwrt/package/broadcom-wl/src/kmod/sbhnddma.h rename openwrt/package/{wlc/src => broadcom-wl/src/wlc}/Makefile (100%) rename openwrt/package/{wlc/src => broadcom-wl/src/wlc}/include/bcmdefs.h (100%) rename openwrt/package/{wlc/src => broadcom-wl/src/wlc}/include/bcmutils.h (100%) rename openwrt/package/{wlc/src => broadcom-wl/src/wlc}/include/proto/802.11.h (100%) rename openwrt/package/{wlc/src => broadcom-wl/src/wlc}/include/proto/bcmeth.h (100%) rename openwrt/package/{wlc/src => broadcom-wl/src/wlc}/include/proto/bcmevent.h (100%) rename openwrt/package/{wlc/src => broadcom-wl/src/wlc}/include/proto/ethernet.h (100%) rename openwrt/package/{wlc/src => broadcom-wl/src/wlc}/include/proto/wpa.h (100%) rename openwrt/package/{wlc/src => broadcom-wl/src/wlc}/include/typedefs.h (100%) rename openwrt/package/{wlc/src => broadcom-wl/src/wlc}/include/wlioctl.h (100%) rename openwrt/package/{wlc/src => broadcom-wl/src/wlc}/include/wlutils.h (100%) rename openwrt/package/{wlc/src => broadcom-wl/src/wlc}/ioctl.c (100%) rename openwrt/package/{wlc/src => broadcom-wl/src/wlc}/wlc.c (100%) delete mode 100644 openwrt/package/wlc/Makefile delete mode 100644 openwrt/target/linux/brcm-2.4/Config.in diff --git a/openwrt/package/broadcom-wl/Makefile b/openwrt/package/broadcom-wl/Makefile new file mode 100644 index 0000000000..782dfdaf57 --- /dev/null +++ b/openwrt/package/broadcom-wl/Makefile @@ -0,0 +1,96 @@ +# $Id: Makefile 2480 2005-11-14 02:07:33Z nbd $ + +include $(TOPDIR)/rules.mk +include $(TOPDIR)/package/kernel.mk + +PKG_NAME:=broadcom-wl +PKG_VERSION:=4.80.9.2 +PKG_RELEASE:=1 +WLC_VERSION:=0.1 + +PKG_BUILD_DIR:=$(KERNEL_BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION) +PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2 +PKG_SOURCE_URL:=http://downloads.openwrt.org/sources +PKG_MD5SUM:=8ff7481425e0b04fc66f2bf950474cbc +PKG_CAT:=bzcat + +include $(TOPDIR)/package/rules.mk + +define Package/kmod-brcm-wl + SECTION:=drivers + CATEGORY:=Drivers + DEPENDS:=@LINUX_2_4_BRCM + DEFAULT:=y + MENU:=1 + TITLE:=Proprietary BCM43xx WiFi driver + DESCRIPTION:=Proprietary Wireless driver for the Broadcom BCM43xx chipset + VERSION:=$(LINUX_VERSION)+$(PKG_VERSION)-$(PKG_RELEASE) +endef + +define Package/wlc + $(call Package/kmod-brcm-wl) + DEPENDS:=kmod-brcm-wl + TITLE:=Setup utility + DESCRIPTION:=Utility for initializing the Broadcom wl driver + VERSION:=$(WLC_VERSION)-$(PKG_RELEASE) +endef + +define Package/wl + $(call Package/wlc) + TITLE:=Utility for changing the driver's parameters + DESCRIPTION:=Utility for changing the Broadcom wl driver's parameters + VERSION:=$(PKG_VERSION)-$(PKG_RELEASE) +endef + +define Package/nas + $(call Package/wl) + TITLE:=Proprietary WPA/WPA2 authenticator + DESCRIPTION:=Proprietary WPA/WPA2 authenticator for the Broadcom wl driver +endef + +define Build/Prepare + $(call Build/Prepare/Default) + $(CP) src/* $(PKG_BUILD_DIR)/ +endef + +define Build/Compile + # Compile the kernel part + $(MAKE) -C "$(LINUX_DIR)" \ + CROSS_COMPILE="$(TARGET_CROSS)" \ + ARCH="$(LINUX_KARCH)" \ + PATH="$(TARGET_PATH)" \ + SUBDIRS="$(PKG_BUILD_DIR)/kmod" \ + modules + + # Compile wlc + $(MAKE) -C $(PKG_BUILD_DIR)/wlc \ + $(TARGET_CONFIGURE_OPTS) \ + CC="$(TARGET_CC)" \ + CFLAGS="-I$(PKG_BUILD_DIR)/wlc/include $(TARGET_CFLAGS)" \ + all +endef + +define Package/kmod-brcm-wl/install + install -d -m0755 $(1)/lib/modules/$(LINUX_VERSION) + install -m0644 $(PKG_BUILD_DIR)/kmod/wl.o $(1)/lib/modules/$(LINUX_VERSION)/ +endef + +define Package/wlc/install + install -d -m0755 $(1)/sbin + install -m0755 $(PKG_BUILD_DIR)/wlc/wlc $(1)/sbin/ +endef + +define Package/wl/install + install -d -m0755 $(1)/usr/sbin + install -m0755 $(PKG_BUILD_DIR)/wl $(1)/usr/sbin/ +endef + +define Package/nas/install + install -d -m0755 $(1)/usr/sbin + install -m0755 $(PKG_BUILD_DIR)/nas $(1)/usr/sbin/ +endef + +$(eval $(call BuildPackage,kmod-brcm-wl)) +$(eval $(call BuildPackage,wlc)) +$(eval $(call BuildPackage,wl)) +$(eval $(call BuildPackage,nas)) diff --git a/openwrt/package/broadcom-wl/src/kmod/Makefile b/openwrt/package/broadcom-wl/src/kmod/Makefile new file mode 100644 index 0000000000..672384035f --- /dev/null +++ b/openwrt/package/broadcom-wl/src/kmod/Makefile @@ -0,0 +1,32 @@ +# +# Makefile for the Broadcom wl driver +# +# Copyright 2004, Broadcom Corporation +# All Rights Reserved. +# +# THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY +# KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM +# SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. +# +# $Id: Makefile,v 1.2 2005/03/29 03:32:18 mbm Exp $ + +EXTRA_CFLAGS += -I$(TOPDIR)/arch/mips/bcm947xx/include -DBCMDRIVER + +O_TARGET := wl_link.o + +obj-y := wl_mod.o +obj-y += bcmutils.o hnddma.o linux_osl.o + +obj-m := $(O_TARGET) + +wl_mod.o: wl_apsta.o + sed -e 's,eth%d,wl%d\x00,g' < $< > $@ + +wl.o: wl_link.o + $(OBJDUMP) -d $< | perl patchtable.pl > patchtable.bin + cat wl_link.o patchtable.bin > $@ + +modules: wl.o + +include $(TOPDIR)/Rules.make diff --git a/openwrt/package/broadcom-wl/src/kmod/bcmip.h b/openwrt/package/broadcom-wl/src/kmod/bcmip.h new file mode 100644 index 0000000000..423a0e5c5c --- /dev/null +++ b/openwrt/package/broadcom-wl/src/kmod/bcmip.h @@ -0,0 +1,101 @@ +/* + * Copyright 2006, Broadcom Corporation + * All Rights Reserved. + * + * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY + * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM + * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. + * + * Fundamental constants relating to IP Protocol + * + * $Id: bcmip.h,v 1.1.1.3 2006/02/27 03:43:16 honor Exp $ + */ + +#ifndef _bcmip_h_ +#define _bcmip_h_ + +/* IPV4 and IPV6 common */ +#define IP_VER_OFFSET 0x0 /* offset to version field */ +#define IP_VER_MASK 0xf0 /* version mask */ +#define IP_VER_SHIFT 4 /* version shift */ +#define IP_VER_4 4 /* version number for IPV4 */ +#define IP_VER_6 6 /* version number for IPV6 */ + +#define IP_VER(ip_body) \ + ((((uint8 *)(ip_body))[IP_VER_OFFSET] & IP_VER_MASK) >> IP_VER_SHIFT) + +#define IP_PROT_ICMP 0x1 /* ICMP protocol */ +#define IP_PROT_TCP 0x6 /* TCP protocol */ +#define IP_PROT_UDP 0x11 /* UDP protocol type */ + +/* IPV4 field offsets */ +#define IPV4_VER_HL_OFFSET 0 /* version and ihl byte offset */ +#define IPV4_TOS_OFFSET 1 /* type of service offset */ +#define IPV4_PROT_OFFSET 9 /* protocol type offset */ +#define IPV4_CHKSUM_OFFSET 10 /* IP header checksum offset */ +#define IPV4_SRC_IP_OFFSET 12 /* src IP addr offset */ +#define IPV4_DEST_IP_OFFSET 16 /* dest IP addr offset */ + +/* IPV4 field decodes */ +#define IPV4_VER_MASK 0xf0 /* IPV4 version mask */ +#define IPV4_VER_SHIFT 4 /* IPV4 version shift */ + +#define IPV4_HLEN_MASK 0x0f /* IPV4 header length mask */ +#define IPV4_HLEN(ipv4_body) (4 * (((uint8 *)(ipv4_body))[IPV4_VER_HL_OFFSET] & IPV4_HLEN_MASK)) + +#define IPV4_ADDR_LEN 4 /* IPV4 address length */ + +#define IPV4_ADDR_NULL(a) ((((uint8 *)(a))[0] | ((uint8 *)(a))[1] | \ + ((uint8 *)(a))[2] | ((uint8 *)(a))[3]) == 0) + +#define IPV4_TOS_DSCP_MASK 0xfc /* DiffServ codepoint mask */ +#define IPV4_TOS_DSCP_SHIFT 2 /* DiffServ codepoint shift */ + +#define IPV4_TOS(ipv4_body) (((uint8 *)(ipv4_body))[IPV4_TOS_OFFSET]) + +#define IPV4_TOS_PREC_MASK 0xe0 /* Historical precedence mask */ +#define IPV4_TOS_PREC_SHIFT 5 /* Historical precedence shift */ + +#define IPV4_TOS_LOWDELAY 0x10 /* Lowest delay requested */ +#define IPV4_TOS_THROUGHPUT 0x8 /* Best throughput requested */ +#define IPV4_TOS_RELIABILITY 0x4 /* Most reliable delivery requested */ + +#define IPV4_PROT(ipv4_body) (((uint8 *)(ipv4_body))[IPV4_PROT_OFFSET]) + +#define IPV4_ADDR_STR_LEN 16 /* Max IP address length in string format */ + +/* IPV6 field offsets */ +#define IPV6_PAYLOAD_LEN_OFFSET 4 /* payload length offset */ +#define IPV6_NEXT_HDR_OFFSET 6 /* next header/protocol offset */ +#define IPV6_HOP_LIMIT_OFFSET 7 /* hop limit offset */ +#define IPV6_SRC_IP_OFFSET 8 /* src IP addr offset */ +#define IPV6_DEST_IP_OFFSET 24 /* dst IP addr offset */ + +/* IPV6 field decodes */ +#define IPV6_TRAFFIC_CLASS(ipv6_body) \ + (((((uint8 *)(ipv6_body))[0] & 0x0f) << 4) | \ + ((((uint8 *)(ipv6_body))[1] & 0xf0) >> 4)) + +#define IPV6_FLOW_LABEL(ipv6_body) \ + (((((uint8 *)(ipv6_body))[1] & 0x0f) << 16) | \ + (((uint8 *)(ipv6_body))[2] << 8) | \ + (((uint8 *)(ipv6_body))[3])) + +#define IPV6_PAYLOAD_LEN(ipv6_body) \ + ((((uint8 *)(ipv6_body))[IPV6_PAYLOAD_LEN_OFFSET + 0] << 8) | \ + ((uint8 *)(ipv6_body))[IPV6_PAYLOAD_LEN_OFFSET + 1]) + +#define IPV6_NEXT_HDR(ipv6_body) \ + (((uint8 *)(ipv6_body))[IPV6_NEXT_HDR_OFFSET]) + +#define IPV6_PROT(ipv6_body) IPV6_NEXT_HDR(ipv6_body) + +#define IPV6_ADDR_LEN 16 /* IPV6 address length */ + +/* IPV4 TOS or IPV6 Traffic Classifier or 0 */ +#define IP_TOS(ip_body) \ + (IP_VER(ip_body) == IP_VER_4 ? IPV4_TOS(ip_body) : \ + IP_VER(ip_body) == IP_VER_6 ? IPV6_TRAFFIC_CLASS(ip_body) : 0) + +#endif /* _bcmip_h_ */ diff --git a/openwrt/package/broadcom-wl/src/kmod/bcmutils.c b/openwrt/package/broadcom-wl/src/kmod/bcmutils.c new file mode 100644 index 0000000000..c264ea500b --- /dev/null +++ b/openwrt/package/broadcom-wl/src/kmod/bcmutils.c @@ -0,0 +1,857 @@ +/* + * Misc useful OS-independent routines. + * + * Copyright 2006, Broadcom Corporation + * All Rights Reserved. + * + * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY + * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM + * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. + * $Id: bcmutils.c,v 1.1.1.12 2006/02/27 03:43:16 honor Exp $ + */ + +#include +#include +#include +#include +#include "linux_osl.h" +#include "pktq.h" +#include +#include +#include +#include +#include +#include "bcmip.h" + +#define ETHER_TYPE_8021Q 0x8100 +#define ETHER_TYPE_IP 0x0800 +#define VLAN_PRI_SHIFT 13 +#define VLAN_PRI_MASK 7 + + +struct ether_header { + uint8 ether_dhost[6]; + uint8 ether_shost[6]; + uint16 ether_type; +} __attribute__((packed)); + + +struct ethervlan_header { + uint8 ether_dhost[6]; + uint8 ether_shost[6]; + uint16 vlan_type; /* 0x8100 */ + uint16 vlan_tag; /* priority, cfi and vid */ + uint16 ether_type; +}; + +/* copy a pkt buffer chain into a buffer */ +uint +pktcopy(osl_t *osh, void *p, uint offset, int len, uchar *buf) +{ + uint n, ret = 0; + + if (len < 0) + len = 4096; /* "infinite" */ + + /* skip 'offset' bytes */ + for (; p && offset; p = PKTNEXT(osh, p)) { + if (offset < (uint)PKTLEN(osh, p)) + break; + offset -= PKTLEN(osh, p); + } + + if (!p) + return 0; + + /* copy the data */ + for (; p && len; p = PKTNEXT(osh, p)) { + n = MIN((uint)PKTLEN(osh, p) - offset, (uint)len); + bcopy(PKTDATA(osh, p) + offset, buf, n); + buf += n; + len -= n; + ret += n; + offset = 0; + } + + return ret; +} + +/* return total length of buffer chain */ +uint +pkttotlen(osl_t *osh, void *p) +{ + uint total; + + total = 0; + for (; p; p = PKTNEXT(osh, p)) + total += PKTLEN(osh, p); + return (total); +} + +/* return the last buffer of chained pkt */ +void * +pktlast(osl_t *osh, void *p) +{ + for (; PKTNEXT(osh, p); p = PKTNEXT(osh, p)) + ; + + return (p); +} + + +/* + * osl multiple-precedence packet queue + * hi_prec is always >= the number of the highest non-empty queue + */ +void * +pktq_penq(struct pktq *pq, int prec, void *p) +{ + struct pktq_prec *q; + + ASSERT(prec >= 0 && prec < pq->num_prec); + ASSERT(PKTLINK(p) == NULL); /* queueing chains not allowed */ + + ASSERT(!pktq_full(pq)); + ASSERT(!pktq_pfull(pq, prec)); + + q = &pq->q[prec]; + + if (q->head) + PKTSETLINK(q->tail, p); + else + q->head = p; + + q->tail = p; + q->len++; + + pq->len++; + + if (pq->hi_prec < prec) + pq->hi_prec = (uint8)prec; + + return p; +} + +void * +pktq_penq_head(struct pktq *pq, int prec, void *p) +{ + struct pktq_prec *q; + + ASSERT(prec >= 0 && prec < pq->num_prec); + ASSERT(PKTLINK(p) == NULL); /* queueing chains not allowed */ + + ASSERT(!pktq_full(pq)); + ASSERT(!pktq_pfull(pq, prec)); + + q = &pq->q[prec]; + + if (q->head == NULL) + q->tail = p; + + PKTSETLINK(p, q->head); + q->head = p; + q->len++; + + pq->len++; + + if (pq->hi_prec < prec) + pq->hi_prec = (uint8)prec; + + return p; +} + +void * +pktq_pdeq(struct pktq *pq, int prec) +{ + struct pktq_prec *q; + void *p; + + ASSERT(prec >= 0 && prec < pq->num_prec); + + q = &pq->q[prec]; + + if ((p = q->head) == NULL) + return NULL; + + if ((q->head = PKTLINK(p)) == NULL) + q->tail = NULL; + + q->len--; + + pq->len--; + + PKTSETLINK(p, NULL); + + return p; +} + +void * +pktq_pdeq_tail(struct pktq *pq, int prec) +{ + struct pktq_prec *q; + void *p, *prev; + + ASSERT(prec >= 0 && prec < pq->num_prec); + + q = &pq->q[prec]; + + if ((p = q->head) == NULL) + return NULL; + + for (prev = NULL; p != q->tail; p = PKTLINK(p)) + prev = p; + + if (prev) + PKTSETLINK(prev, NULL); + else + q->head = NULL; + + q->tail = prev; + q->len--; + + pq->len--; + + return p; +} + +void +pktq_pflush(osl_t *osh, struct pktq *pq, int prec, bool dir) +{ + struct pktq_prec *q; + void *p; + + q = &pq->q[prec]; + p = q->head; + while (p) { + q->head = PKTLINK(p); + PKTSETLINK(p, NULL); + PKTFREE(osh, p, dir); + q->len--; + pq->len--; + p = q->head; + } + ASSERT(q->len == 0); + q->tail = NULL; +} + +bool +pktq_pdel(struct pktq *pq, void *pktbuf, int prec) +{ + struct pktq_prec *q; + void *p; + + ASSERT(prec >= 0 && prec < pq->num_prec); + + if (!pktbuf) + return FALSE; + + q = &pq->q[prec]; + + if (q->head == pktbuf) { + if ((q->head = PKTLINK(pktbuf)) == NULL) + q->tail = NULL; + } else { + for (p = q->head; p && PKTLINK(p) != pktbuf; p = PKTLINK(p)) + ; + if (p == NULL) + return FALSE; + + PKTSETLINK(p, PKTLINK(pktbuf)); + if (q->tail == pktbuf) + q->tail = p; + } + + q->len--; + pq->len--; + PKTSETLINK(pktbuf, NULL); + return TRUE; +} + +void +pktq_init(struct pktq *pq, int num_prec, int max_len) +{ + int prec; + + ASSERT(num_prec > 0 && num_prec <= PKTQ_MAX_PREC); + + bzero(pq, sizeof(*pq)); + + pq->num_prec = (uint16)num_prec; + + pq->max = (uint16)max_len; + + for (prec = 0; prec < num_prec; prec++) + pq->q[prec].max = pq->max; +} + +void * +pktq_deq(struct pktq *pq, int *prec_out) +{ + struct pktq_prec *q; + void *p; + int prec; + + if (pq->len == 0) + return NULL; + + while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL) + pq->hi_prec--; + + q = &pq->q[prec]; + + if ((p = q->head) == NULL) + return NULL; + + if ((q->head = PKTLINK(p)) == NULL) + q->tail = NULL; + + q->len--; + + pq->len--; + + if (prec_out) + *prec_out = prec; + + PKTSETLINK(p, NULL); + + return p; +} + +void * +pktq_deq_tail(struct pktq *pq, int *prec_out) +{ + struct pktq_prec *q; + void *p, *prev; + int prec; + + if (pq->len == 0) + return NULL; + + for (prec = 0; prec < pq->hi_prec; prec++) + if (pq->q[prec].head) + break; + + q = &pq->q[prec]; + + if ((p = q->head) == NULL) + return NULL; + + for (prev = NULL; p != q->tail; p = PKTLINK(p)) + prev = p; + + if (prev) + PKTSETLINK(prev, NULL); + else + q->head = NULL; + + q->tail = prev; + q->len--; + + pq->len--; + + if (prec_out) + *prec_out = prec; + + PKTSETLINK(p, NULL); + + return p; +} + +void * +pktq_peek(struct pktq *pq, int *prec_out) +{ + int prec; + + if (pq->len == 0) + return NULL; + + while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL) + pq->hi_prec--; + + if (prec_out) + *prec_out = prec; + + return (pq->q[prec].head); +} + +void * +pktq_peek_tail(struct pktq *pq, int *prec_out) +{ + int prec; + + if (pq->len == 0) + return NULL; + + for (prec = 0; prec < pq->hi_prec; prec++) + if (pq->q[prec].head) + break; + + if (prec_out) + *prec_out = prec; + + return (pq->q[prec].tail); +} + +void +pktq_flush(osl_t *osh, struct pktq *pq, bool dir) +{ + int prec; + for (prec = 0; prec < pq->num_prec; prec++) + pktq_pflush(osh, pq, prec, dir); + ASSERT(pq->len == 0); +} + +/* Return sum of lengths of a specific set of precedences */ +int +pktq_mlen(struct pktq *pq, uint prec_bmp) +{ + int prec, len; + + len = 0; + + for (prec = 0; prec <= pq->hi_prec; prec++) + if (prec_bmp & (1 << prec)) + len += pq->q[prec].len; + + return len; +} + +/* Priority dequeue from a specific set of precedences */ +void * +pktq_mdeq(struct pktq *pq, uint prec_bmp, int *prec_out) +{ + struct pktq_prec *q; + void *p; + int prec; + + if (pq->len == 0) + return NULL; + + while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL) + pq->hi_prec--; + + while ((prec_bmp & (1 << prec)) == 0 || pq->q[prec].head == NULL) + if (prec-- == 0) + return NULL; + + q = &pq->q[prec]; + + if ((p = q->head) == NULL) + return NULL; + + if ((q->head = PKTLINK(p)) == NULL) + q->tail = NULL; + + q->len--; + + if (prec_out) + *prec_out = prec; + + pq->len--; + + PKTSETLINK(p, NULL); + + return p; +} + +char* +bcmstrcat(char *dest, const char *src) +{ + strcpy(&dest[strlen(dest)], src); + return (dest); +} + +char* +bcm_ether_ntoa(struct ether_addr *ea, char *buf) +{ + sprintf(buf, "%02x:%02x:%02x:%02x:%02x:%02x", + ea->octet[0]&0xff, ea->octet[1]&0xff, ea->octet[2]&0xff, + ea->octet[3]&0xff, ea->octet[4]&0xff, ea->octet[5]&0xff); + return (buf); +} + +/* parse a xx:xx:xx:xx:xx:xx format ethernet address */ +int +bcm_ether_atoe(char *p, struct ether_addr *ea) +{ + int i = 0; + + for (;;) { + ea->octet[i++] = (char) bcm_strtoul(p, &p, 16); + if (!*p++ || i == 6) + break; + } + + return (i == 6); +} + +/* Takes an Ethernet frame and sets out-of-bound PKTPRIO + * Also updates the inplace vlan tag if requested + */ +void +pktsetprio(void *pkt, bool update_vtag) +{ + struct ether_header *eh; + struct ethervlan_header *evh; + uint8 *pktdata; + int priority = 0; + + pktdata = (uint8 *) PKTDATA(NULL, pkt); + ASSERT(ISALIGNED((uintptr)pktdata, sizeof(uint16))); + + eh = (struct ether_header *) pktdata; + + if (ntoh16(eh->ether_type) == ETHER_TYPE_8021Q) { + uint16 vlan_tag; + int vlan_prio, dscp_prio = 0; + + evh = (struct ethervlan_header *)eh; + + vlan_tag = ntoh16(evh->vlan_tag); + vlan_prio = (int) (vlan_tag >> VLAN_PRI_SHIFT) & VLAN_PRI_MASK; + + if (ntoh16(evh->ether_type) == ETHER_TYPE_IP) { + uint8 *ip_body = pktdata + sizeof(struct ethervlan_header); + uint8 tos_tc = IP_TOS(ip_body); + dscp_prio = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT); + } + + /* DSCP priority gets precedence over 802.1P (vlan tag) */ + priority = (dscp_prio != 0) ? dscp_prio : vlan_prio; + + /* + * If the DSCP priority is not the same as the VLAN priority, + * then overwrite the priority field in the vlan tag, with the + * DSCP priority value. This is required for Linux APs because + * the VLAN driver on Linux, overwrites the skb->priority field + * with the priority value in the vlan tag + */ + if (update_vtag && (priority != vlan_prio)) { + vlan_tag &= ~(VLAN_PRI_MASK << VLAN_PRI_SHIFT); + vlan_tag |= (uint16)priority << VLAN_PRI_SHIFT; + evh->vlan_tag = hton16(vlan_tag); + } + } else if (ntoh16(eh->ether_type) == ETHER_TYPE_IP) { + uint8 *ip_body = pktdata + sizeof(struct ether_header); + uint8 tos_tc = IP_TOS(ip_body); + priority = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT); + } + + ASSERT(priority >= 0 && priority <= MAXPRIO); + PKTSETPRIO(pkt, priority); +} + +static char bcm_undeferrstr[BCME_STRLEN]; + +static const char *bcmerrorstrtable[] = BCMERRSTRINGTABLE; + +/* Convert the Error codes into related Error strings */ +const char * +bcmerrorstr(int bcmerror) +{ + int abs_bcmerror; + + abs_bcmerror = ABS(bcmerror); + + /* check if someone added a bcmerror code but forgot to add errorstring */ + ASSERT(ABS(BCME_LAST) == (ARRAYSIZE(bcmerrorstrtable) - 1)); + if ((bcmerror > 0) || (abs_bcmerror > ABS(BCME_LAST))) { + sprintf(bcm_undeferrstr, "undefined Error %d", bcmerror); + return bcm_undeferrstr; + } + + ASSERT((strlen((char*)bcmerrorstrtable[abs_bcmerror])) < BCME_STRLEN); + + return bcmerrorstrtable[abs_bcmerror]; +} + + +int +bcm_iovar_lencheck(const bcm_iovar_t *vi, void *arg, int len, bool set) +{ + int bcmerror = 0; + + /* length check on io buf */ + switch (vi->type) { + case IOVT_BOOL: + case IOVT_INT8: + case IOVT_INT16: + case IOVT_INT32: + case IOVT_UINT8: + case IOVT_UINT16: + case IOVT_UINT32: + /* all integers are int32 sized args at the ioctl interface */ + if (len < (int)sizeof(int)) { + bcmerror = BCME_BUFTOOSHORT; + } + break; + + case IOVT_BUFFER: + /* buffer must meet minimum length requirement */ + if (len < vi->minlen) { + bcmerror = BCME_BUFTOOSHORT; + } + break; + + case IOVT_VOID: + if (!set) { + /* Cannot return nil... */ + bcmerror = BCME_UNSUPPORTED; + } else if (len) { + /* Set is an action w/o parameters */ + bcmerror = BCME_BUFTOOLONG; + } + break; + + default: + /* unknown type for length check in iovar info */ + ASSERT(0); + bcmerror = BCME_UNSUPPORTED; + } + + return bcmerror; +} + +#define CRC_INNER_LOOP(n, c, x) \ + (c) = ((c) >> 8) ^ crc##n##_table[((c) ^ (x)) & 0xff] + +static uint32 crc32_table[256] = { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, + 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, + 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, + 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, + 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, + 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, + 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, + 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, + 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, + 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, + 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, + 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, + 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, + 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, + 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, + 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, + 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, + 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, + 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, + 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, + 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, + 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, + 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, + 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, + 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, + 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, + 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, + 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, + 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, + 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, + 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, + 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, + 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D +}; + +uint32 +hndcrc32( + uint8 *pdata, /* pointer to array of data to process */ + uint nbytes, /* number of input data bytes to process */ + uint32 crc /* either CRC32_INIT_VALUE or previous return value */ +) +{ + uint8 *pend; +#ifdef __mips__ + uint8 tmp[4]; + ulong *tptr = (ulong *)tmp; + + /* in case the beginning of the buffer isn't aligned */ + pend = (uint8 *)((uint)(pdata + 3) & 0xfffffffc); + nbytes -= (pend - pdata); + while (pdata < pend) + CRC_INNER_LOOP(32, crc, *pdata++); + + /* handle bulk of data as 32-bit words */ + pend = pdata + (nbytes & 0xfffffffc); + while (pdata < pend) { + *tptr = *(ulong *)pdata; + pdata += sizeof(ulong *); + CRC_INNER_LOOP(32, crc, tmp[0]); + CRC_INNER_LOOP(32, crc, tmp[1]); + CRC_INNER_LOOP(32, crc, tmp[2]); + CRC_INNER_LOOP(32, crc, tmp[3]); + } + + /* 1-3 bytes at end of buffer */ + pend = pdata + (nbytes & 0x03); + while (pdata < pend) + CRC_INNER_LOOP(32, crc, *pdata++); +#else + pend = pdata + nbytes; + while (pdata < pend) + CRC_INNER_LOOP(32, crc, *pdata++); +#endif /* __mips__ */ + + return crc; +} + + +/* + * Advance from the current 1-byte tag/1-byte length/variable-length value + * triple, to the next, returning a pointer to the next. + * If the current or next TLV is invalid (does not fit in given buffer length), + * NULL is returned. + * *buflen is not modified if the TLV elt parameter is invalid, or is decremented + * by the TLV paramter's length if it is valid. + */ +bcm_tlv_t * +bcm_next_tlv(bcm_tlv_t *elt, int *buflen) +{ + int len; + + /* validate current elt */ + if (!bcm_valid_tlv(elt, *buflen)) + return NULL; + + /* advance to next elt */ + len = elt->len; + elt = (bcm_tlv_t*)(elt->data + len); + *buflen -= (2 + len); + + /* validate next elt */ + if (!bcm_valid_tlv(elt, *buflen)) + return NULL; + + return elt; +} + +/* + * Traverse a string of 1-byte tag/1-byte length/variable-length value + * triples, returning a pointer to the substring whose first element + * matches tag + */ +bcm_tlv_t * +bcm_parse_tlvs(void *buf, int buflen, uint key) +{ + bcm_tlv_t *elt; + int totlen; + + elt = (bcm_tlv_t*)buf; + totlen = buflen; + + /* find tagged parameter */ + while (totlen >= 2) { + int len = elt->len; + + /* validate remaining totlen */ + if ((elt->id == key) && (totlen >= (len + 2))) + return (elt); + + elt = (bcm_tlv_t*)((uint8*)elt + (len + 2)); + totlen -= (len + 2); + } + + return NULL; +} + +/* + * Traverse a string of 1-byte tag/1-byte length/variable-length value + * triples, returning a pointer to the substring whose first element + * matches tag. Stop parsing when we see an element whose ID is greater + * than the target key. + */ +bcm_tlv_t * +bcm_parse_ordered_tlvs(void *buf, int buflen, uint key) +{ + bcm_tlv_t *elt; + int totlen; + + elt = (bcm_tlv_t*)buf; + totlen = buflen; + + /* find tagged parameter */ + while (totlen >= 2) { + uint id = elt->id; + int len = elt->len; + + /* Punt if we start seeing IDs > than target key */ + if (id > key) + return (NULL); + + /* validate remaining totlen */ + if ((id == key) && (totlen >= (len + 2))) + return (elt); + + elt = (bcm_tlv_t*)((uint8*)elt + (len + 2)); + totlen -= (len + 2); + } + return NULL; +} + + +/* Initialization of bcmstrbuf structure */ +void +bcm_binit(struct bcmstrbuf *b, char *buf, uint size) +{ + b->origsize = b->size = size; + b->origbuf = b->buf = buf; +} + +/* Buffer sprintf wrapper to guard against buffer overflow */ +int +bcm_bprintf(struct bcmstrbuf *b, const char *fmt, ...) +{ + va_list ap; + int r; + + va_start(ap, fmt); + r = vsnprintf(b->buf, b->size, fmt, ap); + + /* Non Ansi C99 compliant returns -1, + * Ansi compliant return r >= b->size, + * bcmstdlib returns 0, handle all + */ + if ((r == -1) || (r >= (int)b->size) || (r == 0)) + { + b->size = 0; + } + else + { + b->size -= r; + b->buf += r; + } + + va_end(ap); + + return r; +} diff --git a/openwrt/package/broadcom-wl/src/kmod/hnddma.c b/openwrt/package/broadcom-wl/src/kmod/hnddma.c new file mode 100644 index 0000000000..4336560888 --- /dev/null +++ b/openwrt/package/broadcom-wl/src/kmod/hnddma.c @@ -0,0 +1,1157 @@ +/* + * Generic Broadcom Home Networking Division (HND) DMA module. + * This supports the following chips: BCM42xx, 44xx, 47xx . + * + * Copyright 2006, Broadcom Corporation + * All Rights Reserved. + * + * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY + * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM + * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. + * + * $Id: hnddma.c,v 1.11 2006/04/08 07:12:42 honor Exp $ + */ + +#include +#include +#include +#include "linux_osl.h" +#include +#include +#include +#include +#include + +#include "sbhnddma.h" +#include "hnddma.h" + +/* debug/trace */ +#define DMA_ERROR(args) +#define DMA_TRACE(args) + +/* default dma message level (if input msg_level pointer is null in dma_attach()) */ +static uint dma_msg_level = + 0; + +#define MAXNAMEL 8 /* 8 char names */ + +#define DI_INFO(dmah) (dma_info_t *)dmah + +/* dma engine software state */ +typedef struct dma_info { + struct hnddma_pub hnddma; /* exported structure, don't use hnddma_t, + * which could be const + */ + uint *msg_level; /* message level pointer */ + char name[MAXNAMEL]; /* callers name for diag msgs */ + + void *osh; /* os handle */ + sb_t *sbh; /* sb handle */ + + bool dma64; /* dma64 enabled */ + bool addrext; /* this dma engine supports DmaExtendedAddrChanges */ + + dma32regs_t *d32txregs; /* 32 bits dma tx engine registers */ + dma32regs_t *d32rxregs; /* 32 bits dma rx engine registers */ + dma64regs_t *d64txregs; /* 64 bits dma tx engine registers */ + dma64regs_t *d64rxregs; /* 64 bits dma rx engine registers */ + + uint32 dma64align; /* either 8k or 4k depends on number of dd */ + dma32dd_t *txd32; /* pointer to dma32 tx descriptor ring */ + dma64dd_t *txd64; /* pointer to dma64 tx descriptor ring */ + uint ntxd; /* # tx descriptors tunable */ + uint txin; /* index of next descriptor to reclaim */ + uint txout; /* index of next descriptor to post */ + void **txp; /* pointer to parallel array of pointers to packets */ + osldma_t *tx_dmah; /* DMA TX descriptor ring handle */ + osldma_t **txp_dmah; /* DMA TX packet data handle */ + ulong txdpa; /* physical address of descriptor ring */ + uint txdalign; /* #bytes added to alloc'd mem to align txd */ + uint txdalloc; /* #bytes allocated for the ring */ + + dma32dd_t *rxd32; /* pointer to dma32 rx descriptor ring */ + dma64dd_t *rxd64; /* pointer to dma64 rx descriptor ring */ + uint nrxd; /* # rx descriptors tunable */ + uint rxin; /* index of next descriptor to reclaim */ + uint rxout; /* index of next descriptor to post */ + void **rxp; /* pointer to parallel array of pointers to packets */ + osldma_t *rx_dmah; /* DMA RX descriptor ring handle */ + osldma_t **rxp_dmah; /* DMA RX packet data handle */ + ulong rxdpa; /* physical address of descriptor ring */ + uint rxdalign; /* #bytes added to alloc'd mem to align rxd */ + uint rxdalloc; /* #bytes allocated for the ring */ + + /* tunables */ + uint rxbufsize; /* rx buffer size in bytes, + not including the extra headroom + */ + uint nrxpost; /* # rx buffers to keep posted */ + uint rxoffset; /* rxcontrol offset */ + uint ddoffsetlow; /* add to get dma address of descriptor ring, low 32 bits */ + uint ddoffsethigh; /* high 32 bits */ + uint dataoffsetlow; /* add to get dma address of data buffer, low 32 bits */ + uint dataoffsethigh; /* high 32 bits */ +} dma_info_t; + +/* descriptor bumping macros */ +#define XXD(x, n) ((x) & ((n) - 1)) /* faster than %, but n must be power of 2 */ +#define TXD(x) XXD((x), di->ntxd) +#define RXD(x) XXD((x), di->nrxd) +#define NEXTTXD(i) TXD(i + 1) +#define PREVTXD(i) TXD(i - 1) +#define NEXTRXD(i) RXD(i + 1) +#define NTXDACTIVE(h, t) TXD(t - h) +#define NRXDACTIVE(h, t) RXD(t - h) + +/* macros to convert between byte offsets and indexes */ +#define B2I(bytes, type) ((bytes) / sizeof(type)) +#define I2B(index, type) ((index) * sizeof(type)) + +#define PCI32ADDR_HIGH 0xc0000000 /* address[31:30] */ +#define PCI32ADDR_HIGH_SHIFT 30 /* address[31:30] */ + + +/* common prototypes */ +static bool _dma_isaddrext(dma_info_t *di); +static bool dma32_alloc(dma_info_t *di, uint direction); +static void _dma_detach(dma_info_t *di); +static void _dma_ddtable_init(dma_info_t *di, uint direction, ulong pa); +static void _dma_rxinit(dma_info_t *di); +static void *_dma_rx(dma_info_t *di); +static void _dma_rxfill(dma_info_t *di); +static void _dma_rxreclaim(dma_info_t *di); +static void _dma_rxenable(dma_info_t *di); +static void * _dma_getnextrxp(dma_info_t *di, bool forceall); + +static void _dma_txblock(dma_info_t *di); +static void _dma_txunblock(dma_info_t *di); +static uint _dma_txactive(dma_info_t *di); + +static void* _dma_peeknexttxp(dma_info_t *di); +static uintptr _dma_getvar(dma_info_t *di, char *name); +static void _dma_counterreset(dma_info_t *di); +static void _dma_fifoloopbackenable(dma_info_t *di); + +/* ** 32 bit DMA prototypes */ +static bool dma32_alloc(dma_info_t *di, uint direction); +static bool dma32_txreset(dma_info_t *di); +static bool dma32_rxreset(dma_info_t *di); +static bool dma32_txsuspendedidle(dma_info_t *di); +static int dma32_txfast(dma_info_t *di, void *p0, bool commit); +static void *dma32_getnexttxp(dma_info_t *di, bool forceall); +static void *dma32_getnextrxp(dma_info_t *di, bool forceall); +static void dma32_txrotate(dma_info_t *di); +static bool dma32_rxidle(dma_info_t *di); +static void dma32_txinit(dma_info_t *di); +static bool dma32_txenabled(dma_info_t *di); +static void dma32_txsuspend(dma_info_t *di); +static void dma32_txresume(dma_info_t *di); +static bool dma32_txsuspended(dma_info_t *di); +static void dma32_txreclaim(dma_info_t *di, bool forceall); +static bool dma32_txstopped(dma_info_t *di); +static bool dma32_rxstopped(dma_info_t *di); +static bool dma32_rxenabled(dma_info_t *di); +static bool _dma32_addrext(osl_t *osh, dma32regs_t *dma32regs); + + +static di_fcn_t dma32proc = { + (di_detach_t)_dma_detach, + (di_txinit_t)dma32_txinit, + (di_txreset_t)dma32_txreset, + (di_txenabled_t)dma32_txenabled, + (di_txsuspend_t)dma32_txsuspend, + (di_txresume_t)dma32_txresume, + (di_txsuspended_t)dma32_txsuspended, + (di_txsuspendedidle_t)dma32_txsuspendedidle, + (di_txfast_t)dma32_txfast, + (di_txstopped_t)dma32_txstopped, + (di_txreclaim_t)dma32_txreclaim, + (di_getnexttxp_t)dma32_getnexttxp, + (di_peeknexttxp_t)_dma_peeknexttxp, + (di_txblock_t)_dma_txblock, + (di_txunblock_t)_dma_txunblock, + (di_txactive_t)_dma_txactive, + (di_txrotate_t)dma32_txrotate, + + (di_rxinit_t)_dma_rxinit, + (di_rxreset_t)dma32_rxreset, + (di_rxidle_t)dma32_rxidle, + (di_rxstopped_t)dma32_rxstopped, + (di_rxenable_t)_dma_rxenable, + (di_rxenabled_t)dma32_rxenabled, + (di_rx_t)_dma_rx, + (di_rxfill_t)_dma_rxfill, + (di_rxreclaim_t)_dma_rxreclaim, + (di_getnextrxp_t)_dma_getnextrxp, + + (di_fifoloopbackenable_t)_dma_fifoloopbackenable, + (di_getvar_t)_dma_getvar, + (di_counterreset_t)_dma_counterreset, + + NULL, + NULL, + NULL, + 34 +}; + +hnddma_t * +dma_attach(osl_t *osh, char *name, sb_t *sbh, void *dmaregstx, void *dmaregsrx, + uint ntxd, uint nrxd, uint rxbufsize, uint nrxpost, uint rxoffset, uint *msg_level) +{ + dma_info_t *di; + uint size; + + /* allocate private info structure */ + if ((di = MALLOC(osh, sizeof (dma_info_t))) == NULL) { + return (NULL); + } + bzero((char *)di, sizeof(dma_info_t)); + + di->msg_level = msg_level ? msg_level : &dma_msg_level; + + /* old chips w/o sb is no longer supported */ + ASSERT(sbh != NULL); + + /* check arguments */ + ASSERT(ISPOWEROF2(ntxd)); + ASSERT(ISPOWEROF2(nrxd)); + if (nrxd == 0) + ASSERT(dmaregsrx == NULL); + if (ntxd == 0) + ASSERT(dmaregstx == NULL); + + + /* init dma reg pointer */ + ASSERT(ntxd <= D32MAXDD); + ASSERT(nrxd <= D32MAXDD); + di->d32txregs = (dma32regs_t *)dmaregstx; + di->d32rxregs = (dma32regs_t *)dmaregsrx; + + DMA_TRACE(("%s: dma_attach: %s osh %p ntxd %d nrxd %d rxbufsize %d nrxpost %d " + "rxoffset %d dmaregstx %p dmaregsrx %p\n", + name, "DMA32", osh, ntxd, nrxd, rxbufsize, + nrxpost, rxoffset, dmaregstx, dmaregsrx)); + + /* make a private copy of our callers name */ + strncpy(di->name, name, MAXNAMEL); + di->name[MAXNAMEL-1] = '\0'; + + di->osh = osh; + di->sbh = sbh; + + /* save tunables */ + di->ntxd = ntxd; + di->nrxd = nrxd; + + /* the actual dma size doesn't include the extra headroom */ + if (rxbufsize > BCMEXTRAHDROOM) + di->rxbufsize = rxbufsize - BCMEXTRAHDROOM; + else + di->rxbufsize = rxbufsize; + + di->nrxpost = nrxpost; + di->rxoffset = rxoffset; + + /* + * figure out the DMA physical address offset for dd and data + * for old chips w/o sb, use zero + * for new chips w sb, + * PCI/PCIE: they map silicon backplace address to zero based memory, need offset + * Other bus: use zero + * SB_BUS BIGENDIAN kludge: use sdram swapped region for data buffer, not descriptor + */ + di->ddoffsetlow = 0; + di->dataoffsetlow = 0; + /* for pci bus, add offset */ + if (sbh->bustype == PCI_BUS) { + di->ddoffsetlow = SB_PCI_DMA; + di->ddoffsethigh = 0; + di->dataoffsetlow = di->ddoffsetlow; + di->dataoffsethigh = di->ddoffsethigh; + } + +#if defined(__mips__) && defined(IL_BIGENDIAN) + di->dataoffsetlow = di->dataoffsetlow + SB_SDRAM_SWAPPED; +#endif + + di->addrext = _dma_isaddrext(di); + + /* allocate tx packet pointer vector */ + if (ntxd) { + size = ntxd * sizeof(void *); + if ((di->txp = MALLOC(osh, size)) == NULL) { + DMA_ERROR(("%s: dma_attach: out of tx memory, malloced %d bytes\n", + di->name, MALLOCED(osh))); + goto fail; + } + bzero((char *)di->txp, size); + } + + /* allocate rx packet pointer vector */ + if (nrxd) { + size = nrxd * sizeof(void *); + if ((di->rxp = MALLOC(osh, size)) == NULL) { + DMA_ERROR(("%s: dma_attach: out of rx memory, malloced %d bytes\n", + di->name, MALLOCED(osh))); + goto fail; + } + bzero((char *)di->rxp, size); + } + + /* allocate transmit descriptor ring, only need ntxd descriptors but it must be aligned */ + if (ntxd) { + if (!dma32_alloc(di, DMA_TX)) + goto fail; + } + + /* allocate receive descriptor ring, only need nrxd descriptors but it must be aligned */ + if (nrxd) { + if (!dma32_alloc(di, DMA_RX)) + goto fail; + } + + if ((di->ddoffsetlow == SB_PCI_DMA) && (di->txdpa > SB_PCI_DMA_SZ) && !di->addrext) { + DMA_ERROR(("%s: dma_attach: txdpa 0x%lx: addrext not supported\n", + di->name, di->txdpa)); + goto fail; + } + if ((di->ddoffsetlow == SB_PCI_DMA) && (di->rxdpa > SB_PCI_DMA_SZ) && !di->addrext) { + DMA_ERROR(("%s: dma_attach: rxdpa 0x%lx: addrext not supported\n", + di->name, di->rxdpa)); + goto fail; + } + + DMA_TRACE(("ddoffsetlow 0x%x ddoffsethigh 0x%x dataoffsetlow 0x%x dataoffsethigh " + "0x%x addrext %d\n", di->ddoffsetlow, di->ddoffsethigh, di->dataoffsetlow, + di->dataoffsethigh, di->addrext)); + + /* allocate tx packet pointer vector and DMA mapping vectors */ + if (ntxd) { + + size = ntxd * sizeof(osldma_t **); + if ((di->txp_dmah = (osldma_t **)MALLOC(osh, size)) == NULL) + goto fail; + bzero((char*)di->txp_dmah, size); + }else + di->txp_dmah = NULL; + + /* allocate rx packet pointer vector and DMA mapping vectors */ + if (nrxd) { + + size = nrxd * sizeof(osldma_t **); + if ((di->rxp_dmah = (osldma_t **)MALLOC(osh, size)) == NULL) + goto fail; + bzero((char*)di->rxp_dmah, size); + + } else + di->rxp_dmah = NULL; + + /* initialize opsvec of function pointers */ + di->hnddma.di_fn = dma32proc; + + return ((hnddma_t *)di); + +fail: + _dma_detach(di); + return (NULL); +} + +/* init the tx or rx descriptor */ +static INLINE void +dma32_dd_upd(dma_info_t *di, dma32dd_t *ddring, ulong pa, uint outidx, uint32 *flags, + uint32 bufcount) +{ + /* dma32 uses 32 bits control to fit both flags and bufcounter */ + *flags = *flags | (bufcount & CTRL_BC_MASK); + + if ((di->dataoffsetlow != SB_PCI_DMA) || !(pa & PCI32ADDR_HIGH)) { + W_SM(&ddring[outidx].addr, BUS_SWAP32(pa + di->dataoffsetlow)); + W_SM(&ddring[outidx].ctrl, BUS_SWAP32(*flags)); + } else { + /* address extension */ + uint32 ae; + ASSERT(di->addrext); + ae = (pa & PCI32ADDR_HIGH) >> PCI32ADDR_HIGH_SHIFT; + pa &= ~PCI32ADDR_HIGH; + + *flags |= (ae << CTRL_AE_SHIFT); + W_SM(&ddring[outidx].addr, BUS_SWAP32(pa + di->dataoffsetlow)); + W_SM(&ddring[outidx].ctrl, BUS_SWAP32(*flags)); + } +} + +static bool +_dma32_addrext(osl_t *osh, dma32regs_t *dma32regs) +{ + uint32 w; + + OR_REG(osh, &dma32regs->control, XC_AE); + w = R_REG(osh, &dma32regs->control); + AND_REG(osh, &dma32regs->control, ~XC_AE); + return ((w & XC_AE) == XC_AE); +} + +/* !! may be called with core in reset */ +static void +_dma_detach(dma_info_t *di) +{ + if (di == NULL) + return; + + DMA_TRACE(("%s: dma_detach\n", di->name)); + + /* shouldn't be here if descriptors are unreclaimed */ + ASSERT(di->txin == di->txout); + ASSERT(di->rxin == di->rxout); + + /* free dma descriptor rings */ + if (di->txd32) + DMA_FREE_CONSISTENT(di->osh, ((int8*)di->txd32 - di->txdalign), + di->txdalloc, (di->txdpa - di->txdalign), &di->tx_dmah); + if (di->rxd32) + DMA_FREE_CONSISTENT(di->osh, ((int8*)di->rxd32 - di->rxdalign), + di->rxdalloc, (di->rxdpa - di->rxdalign), &di->rx_dmah); + + /* free packet pointer vectors */ + if (di->txp) + MFREE(di->osh, (void *)di->txp, (di->ntxd * sizeof(void *))); + if (di->rxp) + MFREE(di->osh, (void *)di->rxp, (di->nrxd * sizeof(void *))); + + /* free tx packet DMA handles */ + if (di->txp_dmah) + MFREE(di->osh, (void *)di->txp_dmah, di->ntxd * sizeof(osldma_t **)); + + /* free rx packet DMA handles */ + if (di->rxp_dmah) + MFREE(di->osh, (void *)di->rxp_dmah, di->nrxd * sizeof(osldma_t **)); + + /* free our private info structure */ + MFREE(di->osh, (void *)di, sizeof(dma_info_t)); + +} + +/* return TRUE if this dma engine supports DmaExtendedAddrChanges, otherwise FALSE */ +static bool +_dma_isaddrext(dma_info_t *di) +{ + if (di->d32txregs) + return (_dma32_addrext(di->osh, di->d32txregs)); + else if (di->d32rxregs) + return (_dma32_addrext(di->osh, di->d32rxregs)); + return FALSE; +} + +/* initialize descriptor table base address */ +static void +_dma_ddtable_init(dma_info_t *di, uint direction, ulong pa) +{ + if ((di->ddoffsetlow != SB_PCI_DMA) || !(pa & PCI32ADDR_HIGH)) { + if (direction == DMA_TX) + W_REG(di->osh, &di->d32txregs->addr, (pa + di->ddoffsetlow)); + else + W_REG(di->osh, &di->d32rxregs->addr, (pa + di->ddoffsetlow)); + } else { + /* dma32 address extension */ + uint32 ae; + ASSERT(di->addrext); + + /* shift the high bit(s) from pa to ae */ + ae = (pa & PCI32ADDR_HIGH) >> PCI32ADDR_HIGH_SHIFT; + pa &= ~PCI32ADDR_HIGH; + + if (direction == DMA_TX) { + W_REG(di->osh, &di->d32txregs->addr, (pa + di->ddoffsetlow)); + SET_REG(di->osh, &di->d32txregs->control, XC_AE, ae <osh, &di->d32rxregs->addr, (pa + di->ddoffsetlow)); + SET_REG(di->osh, &di->d32rxregs->control, RC_AE, ae <name)); + OR_REG(di->osh, &di->d32txregs->control, XC_LE); +} + +static void +_dma_rxinit(dma_info_t *di) +{ + DMA_TRACE(("%s: dma_rxinit\n", di->name)); + + if (di->nrxd == 0) + return; + + di->rxin = di->rxout = 0; + + /* clear rx descriptor ring */ + BZERO_SM((void *)di->rxd32, (di->nrxd * sizeof(dma32dd_t))); + _dma_rxenable(di); + _dma_ddtable_init(di, DMA_RX, di->rxdpa); +} + +static void +_dma_rxenable(dma_info_t *di) +{ + DMA_TRACE(("%s: dma_rxenable\n", di->name)); + + W_REG(di->osh, &di->d32rxregs->control, ((di->rxoffset << RC_RO_SHIFT) | RC_RE)); +} + +/* !! rx entry routine, returns a pointer to the next frame received, + * or NULL if there are no more + */ +static void * +_dma_rx(dma_info_t *di) +{ + void *p; + uint len; + int skiplen = 0; + + while ((p = _dma_getnextrxp(di, FALSE))) { + /* skip giant packets which span multiple rx descriptors */ + if (skiplen > 0) { + skiplen -= di->rxbufsize; + if (skiplen < 0) + skiplen = 0; + PKTFREE(di->osh, p, FALSE); + continue; + } + + len = ltoh16(*(uint16*)(PKTDATA(di->osh, p))); + DMA_TRACE(("%s: dma_rx len %d\n", di->name, len)); + + /* bad frame length check */ + if (len > (di->rxbufsize - di->rxoffset)) { + DMA_ERROR(("%s: dma_rx: bad frame length (%d)\n", di->name, len)); + if (len > 0) + skiplen = len - (di->rxbufsize - di->rxoffset); + PKTFREE(di->osh, p, FALSE); + di->hnddma.rxgiants++; + continue; + } + + /* set actual length */ + PKTSETLEN(di->osh, p, (di->rxoffset + len)); + + break; + } + + return (p); +} + +/* post receive buffers */ +static void +_dma_rxfill(dma_info_t *di) +{ + void *p; + uint rxin, rxout; + uint32 flags = 0; + uint n; + uint i; + uint32 pa; + uint extra_offset = 0; + + /* + * Determine how many receive buffers we're lacking + * from the full complement, allocate, initialize, + * and post them, then update the chip rx lastdscr. + */ + + rxin = di->rxin; + rxout = di->rxout; + + n = di->nrxpost - NRXDACTIVE(rxin, rxout); + + DMA_TRACE(("%s: dma_rxfill: post %d\n", di->name, n)); + + if (di->rxbufsize > BCMEXTRAHDROOM) + extra_offset = BCMEXTRAHDROOM; + + for (i = 0; i < n; i++) { + /* the di->rxbufsize doesn't include the extra headroom, we need to add it to the + size to be allocated + */ + if ((p = PKTGET(di->osh, di->rxbufsize + extra_offset, + FALSE)) == NULL) { + DMA_ERROR(("%s: dma_rxfill: out of rxbufs\n", di->name)); + di->hnddma.rxnobuf++; + break; + } + /* reserve an extra headroom, if applicable */ + if (extra_offset) + PKTPULL(di->osh, p, extra_offset); + + /* Do a cached write instead of uncached write since DMA_MAP + * will flush the cache. + */ + *(uint32*)(PKTDATA(di->osh, p)) = 0; + + pa = (uint32) DMA_MAP(di->osh, PKTDATA(di->osh, p), + di->rxbufsize, DMA_RX, p); + + ASSERT(ISALIGNED(pa, 4)); + + /* save the free packet pointer */ + ASSERT(di->rxp[rxout] == NULL); + di->rxp[rxout] = p; + + /* reset flags for each descriptor */ + flags = 0; + if (rxout == (di->nrxd - 1)) + flags = CTRL_EOT; + dma32_dd_upd(di, di->rxd32, pa, rxout, &flags, di->rxbufsize); + rxout = NEXTRXD(rxout); + } + + di->rxout = rxout; + + /* update the chip lastdscr pointer */ + W_REG(di->osh, &di->d32rxregs->ptr, I2B(rxout, dma32dd_t)); +} + +/* like getnexttxp but no reclaim */ +static void * +_dma_peeknexttxp(dma_info_t *di) +{ + uint end, i; + + if (di->ntxd == 0) + return (NULL); + + end = B2I(R_REG(di->osh, &di->d32txregs->status) & XS_CD_MASK, dma32dd_t); + + for (i = di->txin; i != end; i = NEXTTXD(i)) + if (di->txp[i]) + return (di->txp[i]); + + return (NULL); +} + +static void +_dma_rxreclaim(dma_info_t *di) +{ + void *p; + + /* "unused local" warning suppression for OSLs that + * define PKTFREE() without using the di->osh arg + */ + di = di; + + DMA_TRACE(("%s: dma_rxreclaim\n", di->name)); + + while ((p = _dma_getnextrxp(di, TRUE))) + PKTFREE(di->osh, p, FALSE); +} + +static void * +_dma_getnextrxp(dma_info_t *di, bool forceall) +{ + if (di->nrxd == 0) + return (NULL); + + return dma32_getnextrxp(di, forceall); +} + +static void +_dma_txblock(dma_info_t *di) +{ + di->hnddma.txavail = 0; +} + +static void +_dma_txunblock(dma_info_t *di) +{ + di->hnddma.txavail = di->ntxd - NTXDACTIVE(di->txin, di->txout) - 1; +} + +static uint +_dma_txactive(dma_info_t *di) +{ + return (NTXDACTIVE(di->txin, di->txout)); +} + +static void +_dma_counterreset(dma_info_t *di) +{ + /* reset all software counter */ + di->hnddma.rxgiants = 0; + di->hnddma.rxnobuf = 0; + di->hnddma.txnobuf = 0; +} + +/* get the address of the var in order to change later */ +static uintptr +_dma_getvar(dma_info_t *di, char *name) +{ + if (!strcmp(name, "&txavail")) + return ((uintptr) &(di->hnddma.txavail)); + else { + ASSERT(0); + } + return (0); +} + +void +dma_txpioloopback(osl_t *osh, dma32regs_t *regs) +{ + OR_REG(osh, ®s->control, XC_LE); +} + + + +/* 32 bits DMA functions */ +static void +dma32_txinit(dma_info_t *di) +{ + DMA_TRACE(("%s: dma_txinit\n", di->name)); + + if (di->ntxd == 0) + return; + + di->txin = di->txout = 0; + di->hnddma.txavail = di->ntxd - 1; + + /* clear tx descriptor ring */ + BZERO_SM((void *)di->txd32, (di->ntxd * sizeof(dma32dd_t))); + W_REG(di->osh, &di->d32txregs->control, XC_XE); + _dma_ddtable_init(di, DMA_TX, di->txdpa); +} + +static bool +dma32_txenabled(dma_info_t *di) +{ + uint32 xc; + + /* If the chip is dead, it is not enabled :-) */ + xc = R_REG(di->osh, &di->d32txregs->control); + return ((xc != 0xffffffff) && (xc & XC_XE)); +} + +static void +dma32_txsuspend(dma_info_t *di) +{ + DMA_TRACE(("%s: dma_txsuspend\n", di->name)); + + if (di->ntxd == 0) + return; + + OR_REG(di->osh, &di->d32txregs->control, XC_SE); +} + +static void +dma32_txresume(dma_info_t *di) +{ + DMA_TRACE(("%s: dma_txresume\n", di->name)); + + if (di->ntxd == 0) + return; + + AND_REG(di->osh, &di->d32txregs->control, ~XC_SE); +} + +static bool +dma32_txsuspended(dma_info_t *di) +{ + return (di->ntxd == 0) || ((R_REG(di->osh, &di->d32txregs->control) & XC_SE) == XC_SE); +} + +static void +dma32_txreclaim(dma_info_t *di, bool forceall) +{ + void *p; + + DMA_TRACE(("%s: dma_txreclaim %s\n", di->name, forceall ? "all" : "")); + + while ((p = dma32_getnexttxp(di, forceall))) + PKTFREE(di->osh, p, TRUE); +} + +static bool +dma32_txstopped(dma_info_t *di) +{ + return ((R_REG(di->osh, &di->d32txregs->status) & XS_XS_MASK) == XS_XS_STOPPED); +} + +static bool +dma32_rxstopped(dma_info_t *di) +{ + return ((R_REG(di->osh, &di->d32rxregs->status) & RS_RS_MASK) == RS_RS_STOPPED); +} + +static bool +dma32_alloc(dma_info_t *di, uint direction) +{ + uint size; + uint ddlen; + void *va; + + ddlen = sizeof(dma32dd_t); + + size = (direction == DMA_TX) ? (di->ntxd * ddlen) : (di->nrxd * ddlen); + + if (!ISALIGNED(DMA_CONSISTENT_ALIGN, D32RINGALIGN)) + size += D32RINGALIGN; + + + if (direction == DMA_TX) { + if ((va = DMA_ALLOC_CONSISTENT(di->osh, size, &di->txdpa, &di->tx_dmah)) == NULL) { + DMA_ERROR(("%s: dma_attach: DMA_ALLOC_CONSISTENT(ntxd) failed\n", + di->name)); + return FALSE; + } + + di->txd32 = (dma32dd_t *) ROUNDUP((uintptr)va, D32RINGALIGN); + di->txdalign = (uint)((int8*)di->txd32 - (int8*)va); + di->txdpa += di->txdalign; + di->txdalloc = size; + ASSERT(ISALIGNED((uintptr)di->txd32, D32RINGALIGN)); + } else { + if ((va = DMA_ALLOC_CONSISTENT(di->osh, size, &di->rxdpa, &di->rx_dmah)) == NULL) { + DMA_ERROR(("%s: dma_attach: DMA_ALLOC_CONSISTENT(nrxd) failed\n", + di->name)); + return FALSE; + } + di->rxd32 = (dma32dd_t *) ROUNDUP((uintptr)va, D32RINGALIGN); + di->rxdalign = (uint)((int8*)di->rxd32 - (int8*)va); + di->rxdpa += di->rxdalign; + di->rxdalloc = size; + ASSERT(ISALIGNED((uintptr)di->rxd32, D32RINGALIGN)); + } + + return TRUE; +} + +static bool +dma32_txreset(dma_info_t *di) +{ + uint32 status; + + if (di->ntxd == 0) + return TRUE; + + /* suspend tx DMA first */ + W_REG(di->osh, &di->d32txregs->control, XC_SE); + SPINWAIT(((status = (R_REG(di->osh, &di->d32txregs->status) & XS_XS_MASK)) + != XS_XS_DISABLED) && + (status != XS_XS_IDLE) && + (status != XS_XS_STOPPED), + (10000)); + + W_REG(di->osh, &di->d32txregs->control, 0); + SPINWAIT(((status = (R_REG(di->osh, + &di->d32txregs->status) & XS_XS_MASK)) != XS_XS_DISABLED), + 10000); + + /* wait for the last transaction to complete */ + OSL_DELAY(300); + + return (status == XS_XS_DISABLED); +} + +static bool +dma32_rxidle(dma_info_t *di) +{ + DMA_TRACE(("%s: dma_rxidle\n", di->name)); + + if (di->nrxd == 0) + return TRUE; + + return ((R_REG(di->osh, &di->d32rxregs->status) & RS_CD_MASK) == + R_REG(di->osh, &di->d32rxregs->ptr)); +} + +static bool +dma32_rxreset(dma_info_t *di) +{ + uint32 status; + + if (di->nrxd == 0) + return TRUE; + + W_REG(di->osh, &di->d32rxregs->control, 0); + SPINWAIT(((status = (R_REG(di->osh, + &di->d32rxregs->status) & RS_RS_MASK)) != RS_RS_DISABLED), + 10000); + + return (status == RS_RS_DISABLED); +} + +static bool +dma32_rxenabled(dma_info_t *di) +{ + uint32 rc; + + rc = R_REG(di->osh, &di->d32rxregs->control); + return ((rc != 0xffffffff) && (rc & RC_RE)); +} + +static bool +dma32_txsuspendedidle(dma_info_t *di) +{ + if (di->ntxd == 0) + return TRUE; + + if (!(R_REG(di->osh, &di->d32txregs->control) & XC_SE)) + return 0; + + if ((R_REG(di->osh, &di->d32txregs->status) & XS_XS_MASK) != XS_XS_IDLE) + return 0; + + OSL_DELAY(2); + return ((R_REG(di->osh, &di->d32txregs->status) & XS_XS_MASK) == XS_XS_IDLE); +} + +/* !! tx entry routine + * supports full 32bit dma engine buffer addressing so + * dma buffers can cross 4 Kbyte page boundaries. + */ +static int +dma32_txfast(dma_info_t *di, void *p0, bool commit) +{ + void *p, *next; + uchar *data; + uint len; + uint txout; + uint32 flags = 0; + uint32 pa; + + DMA_TRACE(("%s: dma_txfast\n", di->name)); + + txout = di->txout; + + /* + * Walk the chain of packet buffers + * allocating and initializing transmit descriptor entries. + */ + for (p = p0; p; p = next) { + data = PKTDATA(di->osh, p); + len = PKTLEN(di->osh, p); + next = PKTNEXT(di->osh, p); + + /* return nonzero if out of tx descriptors */ + if (NEXTTXD(txout) == di->txin) + goto outoftxd; + + if (len == 0) + continue; + + /* get physical address of buffer start */ + pa = (uint32) DMA_MAP(di->osh, data, len, DMA_TX, p); + + flags = 0; + if (p == p0) + flags |= CTRL_SOF; + if (next == NULL) + flags |= (CTRL_IOC | CTRL_EOF); + if (txout == (di->ntxd - 1)) + flags |= CTRL_EOT; + + dma32_dd_upd(di, di->txd32, pa, txout, &flags, len); + ASSERT(di->txp[txout] == NULL); + + txout = NEXTTXD(txout); + } + + /* if last txd eof not set, fix it */ + if (!(flags & CTRL_EOF)) + W_SM(&di->txd32[PREVTXD(txout)].ctrl, BUS_SWAP32(flags | CTRL_IOC | CTRL_EOF)); + + /* save the packet */ + di->txp[PREVTXD(txout)] = p0; + + /* bump the tx descriptor index */ + di->txout = txout; + + /* kick the chip */ + if (commit) + W_REG(di->osh, &di->d32txregs->ptr, I2B(txout, dma32dd_t)); + + /* tx flow control */ + di->hnddma.txavail = di->ntxd - NTXDACTIVE(di->txin, di->txout) - 1; + + return (0); + +outoftxd: + DMA_ERROR(("%s: dma_txfast: out of txds\n", di->name)); + PKTFREE(di->osh, p0, TRUE); + di->hnddma.txavail = 0; + di->hnddma.txnobuf++; + return (-1); +} + +/* + * Reclaim next completed txd (txds if using chained buffers) and + * return associated packet. + * If 'force' is true, reclaim txd(s) and return associated packet + * regardless of the value of the hardware "curr" pointer. + */ +static void * +dma32_getnexttxp(dma_info_t *di, bool forceall) +{ + uint start, end, i; + void *txp; + + DMA_TRACE(("%s: dma_getnexttxp %s\n", di->name, forceall ? "all" : "")); + + if (di->ntxd == 0) + return (NULL); + + txp = NULL; + + start = di->txin; + if (forceall) + end = di->txout; + else + end = B2I(R_REG(di->osh, &di->d32txregs->status) & XS_CD_MASK, dma32dd_t); + + if ((start == 0) && (end > di->txout)) + goto bogus; + + for (i = start; i != end && !txp; i = NEXTTXD(i)) { + DMA_UNMAP(di->osh, (BUS_SWAP32(R_SM(&di->txd32[i].addr)) - di->dataoffsetlow), + (BUS_SWAP32(R_SM(&di->txd32[i].ctrl)) & CTRL_BC_MASK), + DMA_TX, di->txp[i]); + + W_SM(&di->txd32[i].addr, 0xdeadbeef); + txp = di->txp[i]; + di->txp[i] = NULL; + } + + di->txin = i; + + /* tx flow control */ + di->hnddma.txavail = di->ntxd - NTXDACTIVE(di->txin, di->txout) - 1; + + return (txp); + +bogus: +/* + DMA_ERROR(("dma_getnexttxp: bogus curr: start %d end %d txout %d force %d\n", + start, end, di->txout, forceall)); +*/ + return (NULL); +} + +static void * +dma32_getnextrxp(dma_info_t *di, bool forceall) +{ + uint i; + void *rxp; + + /* if forcing, dma engine must be disabled */ + ASSERT(!forceall || !dma32_rxenabled(di)); + + i = di->rxin; + + /* return if no packets posted */ + if (i == di->rxout) + return (NULL); + + /* ignore curr if forceall */ + if (!forceall && (i == B2I(R_REG(di->osh, &di->d32rxregs->status) & RS_CD_MASK, dma32dd_t))) + return (NULL); + + /* get the packet pointer that corresponds to the rx descriptor */ + rxp = di->rxp[i]; + ASSERT(rxp); + di->rxp[i] = NULL; + + /* clear this packet from the descriptor ring */ + DMA_UNMAP(di->osh, (BUS_SWAP32(R_SM(&di->rxd32[i].addr)) - di->dataoffsetlow), + di->rxbufsize, DMA_RX, rxp); + + W_SM(&di->rxd32[i].addr, 0xdeadbeef); + + di->rxin = NEXTRXD(i); + + return (rxp); +} + +/* + * Rotate all active tx dma ring entries "forward" by (ActiveDescriptor - txin). + */ +static void +dma32_txrotate(dma_info_t *di) +{ + uint ad; + uint nactive; + uint rot; + uint old, new; + uint32 w; + uint first, last; + + ASSERT(dma32_txsuspendedidle(di)); + + nactive = _dma_txactive(di); + ad = B2I(((R_REG(di->osh, &di->d32txregs->status) & XS_AD_MASK) >> XS_AD_SHIFT), dma32dd_t); + rot = TXD(ad - di->txin); + + ASSERT(rot < di->ntxd); + + /* full-ring case is a lot harder - don't worry about this */ + if (rot >= (di->ntxd - nactive)) { + DMA_ERROR(("%s: dma_txrotate: ring full - punt\n", di->name)); + return; + } + + first = di->txin; + last = PREVTXD(di->txout); + + /* move entries starting at last and moving backwards to first */ + for (old = last; old != PREVTXD(first); old = PREVTXD(old)) { + new = TXD(old + rot); + + /* + * Move the tx dma descriptor. + * EOT is set only in the last entry in the ring. + */ + w = BUS_SWAP32(R_SM(&di->txd32[old].ctrl)) & ~CTRL_EOT; + if (new == (di->ntxd - 1)) + w |= CTRL_EOT; + W_SM(&di->txd32[new].ctrl, BUS_SWAP32(w)); + W_SM(&di->txd32[new].addr, R_SM(&di->txd32[old].addr)); + + /* zap the old tx dma descriptor address field */ + W_SM(&di->txd32[old].addr, BUS_SWAP32(0xdeadbeef)); + + /* move the corresponding txp[] entry */ + ASSERT(di->txp[new] == NULL); + di->txp[new] = di->txp[old]; + di->txp[old] = NULL; + } + + /* update txin and txout */ + di->txin = ad; + di->txout = TXD(di->txout + rot); + di->hnddma.txavail = di->ntxd - NTXDACTIVE(di->txin, di->txout) - 1; + + /* kick the chip */ + W_REG(di->osh, &di->d32txregs->ptr, I2B(di->txout, dma32dd_t)); +} + + +uint +dma_addrwidth(sb_t *sbh, void *dmaregs) +{ + dma32regs_t *dma32regs; + osl_t *osh; + + osh = sb_osh(sbh); + + /* Start checking for 32-bit / 30-bit addressing */ + dma32regs = (dma32regs_t *)dmaregs; + + /* For System Backplane, PCIE bus or addrext feature, 32-bits ok */ + if ((BUSTYPE(sbh->bustype) == SB_BUS) || + ((BUSTYPE(sbh->bustype) == PCI_BUS) && sbh->buscoretype == SB_PCIE) || + (_dma32_addrext(osh, dma32regs))) + return (DMADDRWIDTH_32); + + /* Fallthru */ + return (DMADDRWIDTH_30); +} diff --git a/openwrt/package/broadcom-wl/src/kmod/hnddma.h b/openwrt/package/broadcom-wl/src/kmod/hnddma.h new file mode 100644 index 0000000000..de74c067b2 --- /dev/null +++ b/openwrt/package/broadcom-wl/src/kmod/hnddma.h @@ -0,0 +1,156 @@ +/* + * Generic Broadcom Home Networking Division (HND) DMA engine SW interface + * This supports the following chips: BCM42xx, 44xx, 47xx . + * + * Copyright 2006, Broadcom Corporation + * All Rights Reserved. + * + * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY + * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM + * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. + * $Id: hnddma.h,v 1.1.1.13 2006/04/08 06:13:39 honor Exp $ + */ + +#ifndef _hnddma_h_ +#define _hnddma_h_ + +typedef const struct hnddma_pub hnddma_t; + +/* dma function type */ +typedef void (*di_detach_t)(hnddma_t *dmah); +typedef bool (*di_txreset_t)(hnddma_t *dmah); +typedef bool (*di_rxreset_t)(hnddma_t *dmah); +typedef bool (*di_rxidle_t)(hnddma_t *dmah); +typedef void (*di_txinit_t)(hnddma_t *dmah); +typedef bool (*di_txenabled_t)(hnddma_t *dmah); +typedef void (*di_rxinit_t)(hnddma_t *dmah); +typedef void (*di_txsuspend_t)(hnddma_t *dmah); +typedef void (*di_txresume_t)(hnddma_t *dmah); +typedef bool (*di_txsuspended_t)(hnddma_t *dmah); +typedef bool (*di_txsuspendedidle_t)(hnddma_t *dmah); +typedef int (*di_txfast_t)(hnddma_t *dmah, void *p, bool commit); +typedef void (*di_fifoloopbackenable_t)(hnddma_t *dmah); +typedef bool (*di_txstopped_t)(hnddma_t *dmah); +typedef bool (*di_rxstopped_t)(hnddma_t *dmah); +typedef bool (*di_rxenable_t)(hnddma_t *dmah); +typedef bool (*di_rxenabled_t)(hnddma_t *dmah); +typedef void* (*di_rx_t)(hnddma_t *dmah); +typedef void (*di_rxfill_t)(hnddma_t *dmah); +typedef void (*di_txreclaim_t)(hnddma_t *dmah, bool forceall); +typedef void (*di_rxreclaim_t)(hnddma_t *dmah); +typedef uintptr (*di_getvar_t)(hnddma_t *dmah, char *name); +typedef void* (*di_getnexttxp_t)(hnddma_t *dmah, bool forceall); +typedef void* (*di_getnextrxp_t)(hnddma_t *dmah, bool forceall); +typedef void* (*di_peeknexttxp_t)(hnddma_t *dmah); +typedef void (*di_txblock_t)(hnddma_t *dmah); +typedef void (*di_txunblock_t)(hnddma_t *dmah); +typedef uint (*di_txactive_t)(hnddma_t *dmah); +typedef void (*di_txrotate_t)(hnddma_t *dmah); +typedef void (*di_counterreset_t)(hnddma_t *dmah); +typedef char* (*di_dump_t)(hnddma_t *dmah, struct bcmstrbuf *b, bool dumpring); +typedef char* (*di_dumptx_t)(hnddma_t *dmah, struct bcmstrbuf *b, bool dumpring); +typedef char* (*di_dumprx_t)(hnddma_t *dmah, struct bcmstrbuf *b, bool dumpring); + +/* dma opsvec */ +typedef struct di_fcn_s { + di_detach_t detach; + di_txinit_t txinit; + di_txreset_t txreset; + di_txenabled_t txenabled; + di_txsuspend_t txsuspend; + di_txresume_t txresume; + di_txsuspended_t txsuspended; + di_txsuspendedidle_t txsuspendedidle; + di_txfast_t txfast; + di_txstopped_t txstopped; + di_txreclaim_t txreclaim; + di_getnexttxp_t getnexttxp; + di_peeknexttxp_t peeknexttxp; + di_txblock_t txblock; + di_txunblock_t txunblock; + di_txactive_t txactive; + di_txrotate_t txrotate; + + di_rxinit_t rxinit; + di_rxreset_t rxreset; + di_rxidle_t rxidle; + di_rxstopped_t rxstopped; + di_rxenable_t rxenable; + di_rxenabled_t rxenabled; + di_rx_t rx; + di_rxfill_t rxfill; + di_rxreclaim_t rxreclaim; + di_getnextrxp_t getnextrxp; + + di_fifoloopbackenable_t fifoloopbackenable; + di_getvar_t d_getvar; + di_counterreset_t counterreset; + di_dump_t dump; + di_dumptx_t dumptx; + di_dumprx_t dumprx; + uint endnum; +} di_fcn_t; + +/* + * Exported data structure (read-only) + */ +/* export structure */ +struct hnddma_pub { + di_fcn_t di_fn; /* DMA function pointers */ + uint txavail; /* # free tx descriptors */ + + /* rx error counters */ + uint rxgiants; /* rx giant frames */ + uint rxnobuf; /* rx out of dma descriptors */ + /* tx error counters */ + uint txnobuf; /* tx out of dma descriptors */ +}; + + +extern hnddma_t * dma_attach(osl_t *osh, char *name, sb_t *sbh, void *dmaregstx, void *dmaregsrx, + uint ntxd, uint nrxd, uint rxbufsize, uint nrxpost, uint rxoffset, + uint *msg_level); +#define dma_detach(di) ((di)->di_fn.detach(di)) +#define dma_txreset(di) ((di)->di_fn.txreset(di)) +#define dma_rxreset(di) ((di)->di_fn.rxreset(di)) +#define dma_rxidle(di) ((di)->di_fn.rxidle(di)) +#define dma_txinit(di) ((di)->di_fn.txinit(di)) +#define dma_txenabled(di) ((di)->di_fn.txenabled(di)) +#define dma_rxinit(di) ((di)->di_fn.rxinit(di)) +#define dma_txsuspend(di) ((di)->di_fn.txsuspend(di)) +#define dma_txresume(di) ((di)->di_fn.txresume(di)) +#define dma_txsuspended(di) ((di)->di_fn.txsuspended(di)) +#define dma_txsuspendedidle(di) ((di)->di_fn.txsuspendedidle(di)) +#define dma_txfast(di, p, commit) ((di)->di_fn.txfast(di, p, commit)) +#define dma_fifoloopbackenable(di) ((di)->di_fn.fifoloopbackenable(di)) +#define dma_txstopped(di) ((di)->di_fn.txstopped(di)) +#define dma_rxstopped(di) ((di)->di_fn.rxstopped(di)) +#define dma_rxenable(di) ((di)->di_fn.rxenable(di)) +#define dma_rxenabled(di) ((di)->di_fn.rxenabled(di)) +#define dma_rx(di) ((di)->di_fn.rx(di)) +#define dma_rxfill(di) ((di)->di_fn.rxfill(di)) +#define dma_txreclaim(di, forceall) ((di)->di_fn.txreclaim(di, forceall)) +#define dma_rxreclaim(di) ((di)->di_fn.rxreclaim(di)) +#define dma_getvar(di, name) ((di)->di_fn.d_getvar(di, name)) +#define dma_getnexttxp(di, forceall) ((di)->di_fn.getnexttxp(di, forceall)) +#define dma_getnextrxp(di, forceall) ((di)->di_fn.getnextrxp(di, forceall)) +#define dma_peeknexttxp(di) ((di)->di_fn.peeknexttxp(di)) +#define dma_txblock(di) ((di)->di_fn.txblock(di)) +#define dma_txunblock(di) ((di)->di_fn.txunblock(di)) +#define dma_txactive(di) ((di)->di_fn.txactive(di)) +#define dma_txrotate(di) ((di)->di_fn.txrotate(di)) +#define dma_counterreset(di) ((di)->di_fn.counterreset(di)) + +#define DMA_DUMP_SIZE 2048 +/* return addresswidth allowed + * This needs to be done after SB attach but before dma attach. + * SB attach provides ability to probe backplane and dma core capabilities + * This info is needed by DMA_ALLOC_CONSISTENT in dma attach + */ +extern uint dma_addrwidth(sb_t *sbh, void *dmaregs); + +/* pio helpers */ +void dma_txpioloopback(osl_t *osh, dma32regs_t *); + +#endif /* _hnddma_h_ */ diff --git a/openwrt/package/broadcom-wl/src/kmod/linux_osl.c b/openwrt/package/broadcom-wl/src/kmod/linux_osl.c new file mode 100644 index 0000000000..d702961032 --- /dev/null +++ b/openwrt/package/broadcom-wl/src/kmod/linux_osl.c @@ -0,0 +1,269 @@ +/* + * Linux OS Independent Layer + * + * Copyright 2006, Broadcom Corporation + * All Rights Reserved. + * + * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY + * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM + * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. + * + * $Id: linux_osl.c,v 1.1.1.14 2006/04/08 06:13:39 honor Exp $ + */ + +#define LINUX_OSL + +#include +#include +#include +#include +#include +#include +#include "linux_osl.h" +#include +#include +#ifdef mips +#include +#endif /* mips */ +#include + +#define PCI_CFG_RETRY 10 + +#define OS_HANDLE_MAGIC 0x1234abcd /* Magic # to recognise osh */ +#define BCM_MEM_FILENAME_LEN 24 /* Mem. filename length */ + +typedef struct bcm_mem_link { + struct bcm_mem_link *prev; + struct bcm_mem_link *next; + uint size; + int line; + char file[BCM_MEM_FILENAME_LEN]; +} bcm_mem_link_t; + +static int16 linuxbcmerrormap[] = \ +{ 0, /* 0 */ + -EINVAL, /* BCME_ERROR */ + -EINVAL, /* BCME_BADARG */ + -EINVAL, /* BCME_BADOPTION */ + -EINVAL, /* BCME_NOTUP */ + -EINVAL, /* BCME_NOTDOWN */ + -EINVAL, /* BCME_NOTAP */ + -EINVAL, /* BCME_NOTSTA */ + -EINVAL, /* BCME_BADKEYIDX */ + -EINVAL, /* BCME_RADIOOFF */ + -EINVAL, /* BCME_NOTBANDLOCKED */ + -EINVAL, /* BCME_NOCLK */ + -EINVAL, /* BCME_BADRATESET */ + -EINVAL, /* BCME_BADBAND */ + -E2BIG, /* BCME_BUFTOOSHORT */ + -E2BIG, /* BCME_BUFTOOLONG */ + -EBUSY, /* BCME_BUSY */ + -EINVAL, /* BCME_NOTASSOCIATED */ + -EINVAL, /* BCME_BADSSIDLEN */ + -EINVAL, /* BCME_OUTOFRANGECHAN */ + -EINVAL, /* BCME_BADCHAN */ + -EFAULT, /* BCME_BADADDR */ + -ENOMEM, /* BCME_NORESOURCE */ + -EOPNOTSUPP, /* BCME_UNSUPPORTED */ + -EMSGSIZE, /* BCME_BADLENGTH */ + -EINVAL, /* BCME_NOTREADY */ + -EPERM, /* BCME_NOTPERMITTED */ + -ENOMEM, /* BCME_NOMEM */ + -EINVAL, /* BCME_ASSOCIATED */ + -ERANGE, /* BCME_RANGE */ + -EINVAL, /* BCME_NOTFOUND */ + -EINVAL, /* BCME_WME_NOT_ENABLED */ + -EINVAL, /* BCME_TSPEC_NOTFOUND */ + -EINVAL, /* BCME_ACM_NOTSUPPORTED */ + -EINVAL, /* BCME_NOT_WME_ASSOCIATION */ + -EIO, /* BCME_SDIO_ERROR */ + -ENODEV /* BCME_DONGLE_DOWN */ +}; + +/* translate bcmerrors into linux errors */ +int +osl_error(int bcmerror) +{ + int abs_bcmerror; + int array_size = ARRAYSIZE(linuxbcmerrormap); + + abs_bcmerror = ABS(bcmerror); + + if (bcmerror > 0) + abs_bcmerror = 0; + + else if (abs_bcmerror >= array_size) + abs_bcmerror = BCME_ERROR; + + return linuxbcmerrormap[abs_bcmerror]; +} + +osl_t * +osl_attach(void *pdev, bool pkttag) +{ + osl_t *osh; + + osh = kmalloc(sizeof(osl_t), GFP_ATOMIC); + ASSERT(osh); + + bzero(osh, sizeof(osl_t)); + + /* + * check the cases where + * 1.Error code Added to bcmerror table, but forgot to add it to the OS + * dependent error code + * 2. Error code is added to the bcmerror table, but forgot to add the + * corresponding errorstring(dummy call to bcmerrorstr) + */ + bcmerrorstr(0); + ASSERT(ABS(BCME_LAST) == (ARRAYSIZE(linuxbcmerrormap) - 1)); + + osh->magic = OS_HANDLE_MAGIC; + osh->malloced = 0; + osh->failed = 0; + osh->dbgmem_list = NULL; + osh->pdev = pdev; + osh->pub.pkttag = pkttag; + + return osh; +} + +void +osl_detach(osl_t *osh) +{ + if (osh == NULL) + return; + + ASSERT(osh->magic == OS_HANDLE_MAGIC); + kfree(osh); +} + +/* Return a new packet. zero out pkttag */ +void* +osl_pktget(osl_t *osh, uint len, bool send) +{ + struct sk_buff *skb; + + if ((skb = dev_alloc_skb(len))) { + skb_put(skb, len); + skb->priority = 0; + +#ifdef BCMDBG_PKT + pktlist_add(&(osh->pktlist), (void *) skb); +#endif /* BCMDBG_PKT */ + + osh->pub.pktalloced++; + } + + return ((void*) skb); +} + +/* Free the driver packet. Free the tag if present */ +void +osl_pktfree(osl_t *osh, void *p) +{ + struct sk_buff *skb, *nskb; + + skb = (struct sk_buff*) p; + + /* perversion: we use skb->next to chain multi-skb packets */ + while (skb) { + nskb = skb->next; + skb->next = NULL; + +#ifdef BCMDBG_PKT + pktlist_remove(&(osh->pktlist), (void *) skb); +#endif /* BCMDBG_PKT */ + + if (skb->destructor) { + /* cannot kfree_skb() on hard IRQ (net/core/skbuff.c) if destructor exists + */ + dev_kfree_skb_any(skb); + } else { + /* can free immediately (even in_irq()) if destructor does not exist */ + dev_kfree_skb(skb); + } + + osh->pub.pktalloced--; + + skb = nskb; + } +} + +void* +osl_malloc(osl_t *osh, uint size) +{ + void *addr; + + /* only ASSERT if osh is defined */ + if (osh) + ASSERT(osh->magic == OS_HANDLE_MAGIC); + + if ((addr = kmalloc(size, GFP_ATOMIC)) == NULL) { + if (osh) + osh->failed++; + return (NULL); + } + if (osh) + osh->malloced += size; + + return (addr); +} + +void +osl_mfree(osl_t *osh, void *addr, uint size) +{ + if (osh) { + ASSERT(osh->magic == OS_HANDLE_MAGIC); + osh->malloced -= size; + } + kfree(addr); +} + +uint +osl_malloced(osl_t *osh) +{ + ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); + return (osh->malloced); +} + +uint osl_malloc_failed(osl_t *osh) +{ + ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); + return (osh->failed); +} + +#undef osl_delay +void +osl_delay(uint usec) +{ + OSL_DELAY(usec); +} + +/* Clone a packet. + * The pkttag contents are NOT cloned. + */ +void * +osl_pktdup(osl_t *osh, void *skb) +{ + void * p; + + if ((p = skb_clone((struct sk_buff*)skb, GFP_ATOMIC)) == NULL) + return NULL; + + /* skb_clone copies skb->cb.. we don't want that */ + if (osh->pub.pkttag) + bzero((void*)((struct sk_buff *)p)->cb, OSL_PKTTAG_SZ); + + /* Increment the packet counter */ + osh->pub.pktalloced++; + return (p); +} + +uint +osl_pktalloced(osl_t *osh) +{ + return (osh->pub.pktalloced); +} + diff --git a/openwrt/package/broadcom-wl/src/kmod/linux_osl.h b/openwrt/package/broadcom-wl/src/kmod/linux_osl.h new file mode 100644 index 0000000000..f6af6124c6 --- /dev/null +++ b/openwrt/package/broadcom-wl/src/kmod/linux_osl.h @@ -0,0 +1,171 @@ +/* + * Linux OS Independent Layer + * + * Copyright 2006, Broadcom Corporation + * All Rights Reserved. + * + * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY + * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM + * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. + * + * $Id: linux_osl.h,v 1.1.1.13 2006/04/08 06:13:39 honor Exp $ + */ + +#ifndef _linux_osl_h_ +#define _linux_osl_h_ + +#include +#include +#include + +#define OSL_PKTTAG_SZ 32 /* Size of PktTag */ + +/* osl handle type forward declaration */ +typedef struct osl_dmainfo osldma_t; + +/* OSL initialization */ +extern osl_t *osl_attach(void *pdev, bool pkttag); +extern void osl_detach(osl_t *osh); + +/* host/bus architecture-specific byte swap */ +#define BUS_SWAP32(v) (v) +#define MALLOC_FAILED(osh) osl_malloc_failed((osh)) + +extern void *osl_malloc(osl_t *osh, uint size); +extern void osl_mfree(osl_t *osh, void *addr, uint size); +extern uint osl_malloced(osl_t *osh); +extern uint osl_malloc_failed(osl_t *osh); + +/* API for DMA addressing capability */ +#define DMA_MAP(osh, va, size, direction, p) \ + osl_dma_map((osh), (va), (size), (direction)) +#define DMA_UNMAP(osh, pa, size, direction, p) \ + osl_dma_unmap((osh), (pa), (size), (direction)) +static inline uint +osl_dma_map(void *osh, void *va, uint size, int direction) +{ + int dir; + struct pci_dev *dev; + + dev = (osh == NULL ? NULL : ((osl_t *)osh)->pdev); + dir = (direction == DMA_TX)? PCI_DMA_TODEVICE: PCI_DMA_FROMDEVICE; + return (pci_map_single(dev, va, size, dir)); +} + +static inline void +osl_dma_unmap(void *osh, uint pa, uint size, int direction) +{ + int dir; + struct pci_dev *dev; + + dev = (osh == NULL ? NULL : ((osl_t *)osh)->pdev); + dir = (direction == DMA_TX)? PCI_DMA_TODEVICE: PCI_DMA_FROMDEVICE; + pci_unmap_single(dev, (uint32)pa, size, dir); +} + +#define OSL_DMADDRWIDTH(osh, addrwidth) do {} while (0) +#define DMA_CONSISTENT_ALIGN PAGE_SIZE +#define DMA_ALLOC_CONSISTENT(osh, size, pap, dmah) \ + osl_dma_alloc_consistent((osh), (size), (pap)) +#define DMA_FREE_CONSISTENT(osh, va, size, pa, dmah) \ + osl_dma_free_consistent((osh), (void*)(va), (size), (pa)) +static inline void* +osl_dma_alloc_consistent(osl_t *osh, uint size, ulong *pap) +{ + return (pci_alloc_consistent(osh->pdev, size, (dma_addr_t*)pap)); +} + +static inline void +osl_dma_free_consistent(osl_t *osh, void *va, uint size, ulong pa) +{ + pci_free_consistent(osh->pdev, size, va, (dma_addr_t)pa); +} + + +/* register access macros */ +#if defined(BCMJTAG) +#include +#define R_REG(osh, r) bcmjtag_read(NULL, (uint32)(r), sizeof(*(r))) +#define W_REG(osh, r, v) bcmjtag_write(NULL, (uint32)(r), (uint32)(v), sizeof(*(r))) +#endif /* defined(BCMSDIO) */ + +/* packet primitives */ +#define PKTGET(osh, len, send) osl_pktget((osh), (len), (send)) +#define PKTFREE(osh, skb, send) osl_pktfree((osh), (skb)) +#define PKTDATA(osh, skb) (((struct sk_buff*)(skb))->data) +#define PKTLEN(osh, skb) (((struct sk_buff*)(skb))->len) +#define PKTHEADROOM(osh, skb) (PKTDATA(osh, skb)-(((struct sk_buff*)(skb))->head)) +#define PKTTAILROOM(osh, skb) ((((struct sk_buff*)(skb))->end)-(((struct sk_buff*)(skb))->tail)) +#define PKTNEXT(osh, skb) (((struct sk_buff*)(skb))->next) +#define PKTSETNEXT(osh, skb, x) (((struct sk_buff*)(skb))->next = (struct sk_buff*)(x)) +#define PKTSETLEN(osh, skb, len) __skb_trim((struct sk_buff*)(skb), (len)) +#define PKTPUSH(osh, skb, bytes) skb_push((struct sk_buff*)(skb), (bytes)) +#define PKTPULL(osh, skb, bytes) skb_pull((struct sk_buff*)(skb), (bytes)) +#define PKTDUP(osh, skb) osl_pktdup((osh), (skb)) +#define PKTTAG(skb) ((void*)(((struct sk_buff*)(skb))->cb)) +#define PKTALLOCED(osh) osl_pktalloced((osh)) +#define PKTLIST_DUMP(osh, buf) + +/* Convert a native(OS) packet to driver packet. + * In the process, native packet is destroyed, there is no copying + * Also, a packettag is zeroed out + */ +static INLINE void * +osl_pkt_frmnative(struct osl_pubinfo *osh, struct sk_buff *skb) +{ + struct sk_buff *nskb; + + if (osh->pkttag) + bzero((void*)skb->cb, OSL_PKTTAG_SZ); + + /* Increment the packet counter */ + for (nskb = skb; nskb; nskb = nskb->next) { + osh->pktalloced++; + } + + return (void *)skb; +} +#define PKTFRMNATIVE(osh, skb) osl_pkt_frmnative(((struct osl_pubinfo *)osh), \ + (struct sk_buff*)(skb)) + +/* Convert a driver packet to native(OS) packet + * In the process, packettag is zeroed out before sending up + * IP code depends on skb->cb to be setup correctly with various options + * In our case, that means it should be 0 + */ +static INLINE struct sk_buff * +osl_pkt_tonative(struct osl_pubinfo *osh, void *pkt) +{ + struct sk_buff *nskb; + + if (osh->pkttag) + bzero(((struct sk_buff*)pkt)->cb, OSL_PKTTAG_SZ); + + /* Decrement the packet counter */ + for (nskb = (struct sk_buff *)pkt; nskb; nskb = nskb->next) { + osh->pktalloced--; + } + + return (struct sk_buff *)pkt; +} +#define PKTTONATIVE(osh, pkt) osl_pkt_tonative((struct osl_pubinfo *)(osh), (pkt)) + +#define PKTLINK(skb) (((struct sk_buff*)(skb))->prev) +#define PKTSETLINK(skb, x) (((struct sk_buff*)(skb))->prev = (struct sk_buff*)(x)) +#define PKTPRIO(skb) (((struct sk_buff*)(skb))->priority) +#define PKTSETPRIO(skb, x) (((struct sk_buff*)(skb))->priority = (x)) +#define PKTSHARED(skb) (((struct sk_buff*)(skb))->cloned) + +extern void *osl_pktget(osl_t *osh, uint len, bool send); +extern void osl_pktfree(osl_t *osh, void *skb); +extern void *osl_pktdup(osl_t *osh, void *skb); +extern uint osl_pktalloced(osl_t *osh); + +#define OSL_ERROR(bcmerror) osl_error(bcmerror) +extern int osl_error(int bcmerror); + +/* the largest reasonable packet buffer driver uses for ethernet MTU in bytes */ +#define PKTBUFSZ 2048 /* largest reasonable packet buffer, driver uses for ethernet MTU */ + +#endif /* _linux_osl_h_ */ diff --git a/openwrt/package/broadcom-wl/src/kmod/patchtable.pl b/openwrt/package/broadcom-wl/src/kmod/patchtable.pl new file mode 100644 index 0000000000..6144d8b925 --- /dev/null +++ b/openwrt/package/broadcom-wl/src/kmod/patchtable.pl @@ -0,0 +1,54 @@ +#!/usr/bin/perl +use strict; + +my $TABLE = pack("V", 0xbadc0ded); +my $TABLE_SIZE = 512; +my $SLT1 = "\x01\x00\x00\x00"; +my $SLT2 = "\x02\x00\x00\x00"; +my $ACKW = "\x03\x00\x00\x00"; +my $PTABLE_END = "\xff\xff\xff\xff"; + +my $addr = ""; +my $opcode = ""; +my $function = ""; + +sub add_entry { + my $key = shift; + my $value = shift; + my $default = shift; + + $TABLE .= $key; + $TABLE .= pack("V", $value); + $TABLE .= pack("V", $default); +} + +while (<>) { + $addr = $opcode = ""; + /^\w{8}\s*<(.*)>:$/ and $function = $1; + /^\s*(\w+):\s*(\w{8})\s*/ and do { + $addr = $1; + $opcode = $2; + }; + + ($function eq 'wlc_update_slot_timing') and do { + # li a2,9 -- short slot time + ($opcode eq '24060009') and add_entry($SLT1, hex($addr), hex($opcode)); + # li v0,519 -- 510 + short slot time + ($opcode eq '24020207') and add_entry($SLT2, hex($addr), hex($opcode)); + + # li a2,20 -- long slot time + ($opcode eq '24060014') and add_entry($SLT1, hex($addr), hex($opcode)); + # li v0,530 -- 510 + long slot time + ($opcode eq '24020212') and add_entry($SLT2, hex($addr), hex($opcode)); + }; + ($function eq 'wlc_d11hdrs') and do { + # ori s6,s6,0x1 -- ack flag (new) + ($opcode eq '36d60001') and add_entry($ACKW, hex($addr), hex($opcode)); + # ori s3,s3,0x1 -- ack flag (old) + ($opcode eq '36730001') and add_entry($ACKW, hex($addr), hex($opcode)); + } +} + +$TABLE .= $PTABLE_END; +$TABLE .= ("\x00" x ($TABLE_SIZE - length($TABLE))); +print $TABLE; diff --git a/openwrt/package/broadcom-wl/src/kmod/pktq.h b/openwrt/package/broadcom-wl/src/kmod/pktq.h new file mode 100644 index 0000000000..7fe21815e8 --- /dev/null +++ b/openwrt/package/broadcom-wl/src/kmod/pktq.h @@ -0,0 +1,97 @@ +/* + * Misc useful os-independent macros and functions. + * + * Copyright 2006, Broadcom Corporation + * All Rights Reserved. + * + * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY + * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM + * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. + * $Id: bcmutils.h,v 1.1.1.16 2006/04/08 06:13:39 honor Exp $ + */ + +#ifndef _pktq_h_ +#define _pktq_h_ +#include + +/* osl multi-precedence packet queue */ + +#define PKTQ_LEN_DEFAULT 128 /* Max 128 packets */ +#define PKTQ_MAX_PREC 16 /* Maximum precedence levels */ + +struct pktq { + struct pktq_prec { + void *head; /* first packet to dequeue */ + void *tail; /* last packet to dequeue */ + uint16 len; /* number of queued packets */ + uint16 max; /* maximum number of queued packets */ + } q[PKTQ_MAX_PREC]; + uint16 num_prec; /* number of precedences in use */ + uint16 hi_prec; /* rapid dequeue hint (>= highest non-empty prec) */ + uint16 max; /* total max packets */ + uint16 len; /* total number of packets */ +}; + +#define PKTQ_PREC_ITER(pq, prec) for (prec = (pq)->num_prec - 1; prec >= 0; prec--) + +/* forward definition of ether_addr structure used by some function prototypes */ + +struct ether_addr; + +/* operations on a specific precedence in packet queue */ + +#define pktq_psetmax(pq, prec, _max) ((pq)->q[prec].max = (_max)) +#define pktq_plen(pq, prec) ((pq)->q[prec].len) +#define pktq_pavail(pq, prec) ((pq)->q[prec].max - (pq)->q[prec].len) +#define pktq_pfull(pq, prec) ((pq)->q[prec].len >= (pq)->q[prec].max) +#define pktq_pempty(pq, prec) ((pq)->q[prec].len == 0) + +#define pktq_ppeek(pq, prec) ((pq)->q[prec].head) +#define pktq_ppeek_tail(pq, prec) ((pq)->q[prec].tail) + +extern void *pktq_penq(struct pktq *pq, int prec, void *p); +extern void *pktq_penq_head(struct pktq *pq, int prec, void *p); +extern void *pktq_pdeq(struct pktq *pq, int prec); +extern void *pktq_pdeq_tail(struct pktq *pq, int prec); +/* Empty the queue at particular precedence level */ +extern void pktq_pflush(osl_t *osh, struct pktq *pq, int prec, bool dir); +/* Remove a specified packet from its queue */ +extern bool pktq_pdel(struct pktq *pq, void *p, int prec); + +/* operations on a set of precedences in packet queue */ + +extern int pktq_mlen(struct pktq *pq, uint prec_bmp); +extern void *pktq_mdeq(struct pktq *pq, uint prec_bmp, int *prec_out); + +/* operations on packet queue as a whole */ + +#define pktq_len(pq) ((int)(pq)->len) +#define pktq_max(pq) ((int)(pq)->max) +#define pktq_avail(pq) ((int)((pq)->max - (pq)->len)) +#define pktq_full(pq) ((pq)->len >= (pq)->max) +#define pktq_empty(pq) ((pq)->len == 0) + +/* operations for single precedence queues */ +#define pktenq(pq, p) pktq_penq((pq), 0, (p)) +#define pktenq_head(pq, p) pktq_penq_head((pq), 0, (p)) +#define pktdeq(pq) pktq_pdeq((pq), 0) +#define pktdeq_tail(pq) pktq_pdeq_tail((pq), 0) + +extern void pktq_init(struct pktq *pq, int num_prec, int max_len); +/* prec_out may be NULL if caller is not interested in return value */ +extern void *pktq_deq(struct pktq *pq, int *prec_out); +extern void *pktq_deq_tail(struct pktq *pq, int *prec_out); +extern void *pktq_peek(struct pktq *pq, int *prec_out); +extern void *pktq_peek_tail(struct pktq *pq, int *prec_out); +extern void pktq_flush(osl_t *osh, struct pktq *pq, bool dir); /* Empty the entire queue */ + +/* externs */ +/* packet */ +extern uint pktcopy(osl_t *osh, void *p, uint offset, int len, uchar *buf); +extern uint pkttotlen(osl_t *osh, void *p); +extern void *pktlast(osl_t *osh, void *p); + +extern void pktsetprio(void *pkt, bool update_vtag); + +#endif /* _pktq_h_ */ diff --git a/openwrt/package/broadcom-wl/src/kmod/sbhnddma.h b/openwrt/package/broadcom-wl/src/kmod/sbhnddma.h new file mode 100644 index 0000000000..a26db7395e --- /dev/null +++ b/openwrt/package/broadcom-wl/src/kmod/sbhnddma.h @@ -0,0 +1,284 @@ +/* + * Generic Broadcom Home Networking Division (HND) DMA engine HW interface + * This supports the following chips: BCM42xx, 44xx, 47xx . + * + * Copyright 2006, Broadcom Corporation + * All Rights Reserved. + * + * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY + * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM + * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. + * + * $Id: sbhnddma.h,v 1.1.1.2 2006/02/27 03:43:16 honor Exp $ + */ + +#ifndef _sbhnddma_h_ +#define _sbhnddma_h_ + +/* DMA structure: + * support two DMA engines: 32 bits address or 64 bit addressing + * basic DMA register set is per channel(transmit or receive) + * a pair of channels is defined for convenience + */ + + +/* 32 bits addressing */ + +/* dma registers per channel(xmt or rcv) */ +typedef volatile struct { + uint32 control; /* enable, et al */ + uint32 addr; /* descriptor ring base address (4K aligned) */ + uint32 ptr; /* last descriptor posted to chip */ + uint32 status; /* current active descriptor, et al */ +} dma32regs_t; + +typedef volatile struct { + dma32regs_t xmt; /* dma tx channel */ + dma32regs_t rcv; /* dma rx channel */ +} dma32regp_t; + +typedef volatile struct { /* diag access */ + uint32 fifoaddr; /* diag address */ + uint32 fifodatalow; /* low 32bits of data */ + uint32 fifodatahigh; /* high 32bits of data */ + uint32 pad; /* reserved */ +} dma32diag_t; + +/* + * DMA Descriptor + * Descriptors are only read by the hardware, never written back. + */ +typedef volatile struct { + uint32 ctrl; /* misc control bits & bufcount */ + uint32 addr; /* data buffer address */ +} dma32dd_t; + +/* + * Each descriptor ring must be 4096byte aligned, and fit within a single 4096byte page. + */ +#define D32MAXRINGSZ 4096 +#define D32RINGALIGN 4096 +#define D32MAXDD (D32MAXRINGSZ / sizeof (dma32dd_t)) + +/* transmit channel control */ +#define XC_XE ((uint32)1 << 0) /* transmit enable */ +#define XC_SE ((uint32)1 << 1) /* transmit suspend request */ +#define XC_LE ((uint32)1 << 2) /* loopback enable */ +#define XC_FL ((uint32)1 << 4) /* flush request */ +#define XC_AE ((uint32)3 << 16) /* address extension bits */ +#define XC_AE_SHIFT 16 + +/* transmit descriptor table pointer */ +#define XP_LD_MASK 0xfff /* last valid descriptor */ + +/* transmit channel status */ +#define XS_CD_MASK 0x0fff /* current descriptor pointer */ +#define XS_XS_MASK 0xf000 /* transmit state */ +#define XS_XS_SHIFT 12 +#define XS_XS_DISABLED 0x0000 /* disabled */ +#define XS_XS_ACTIVE 0x1000 /* active */ +#define XS_XS_IDLE 0x2000 /* idle wait */ +#define XS_XS_STOPPED 0x3000 /* stopped */ +#define XS_XS_SUSP 0x4000 /* suspend pending */ +#define XS_XE_MASK 0xf0000 /* transmit errors */ +#define XS_XE_SHIFT 16 +#define XS_XE_NOERR 0x00000 /* no error */ +#define XS_XE_DPE 0x10000 /* descriptor protocol error */ +#define XS_XE_DFU 0x20000 /* data fifo underrun */ +#define XS_XE_BEBR 0x30000 /* bus error on buffer read */ +#define XS_XE_BEDA 0x40000 /* bus error on descriptor access */ +#define XS_AD_MASK 0xfff00000 /* active descriptor */ +#define XS_AD_SHIFT 20 + +/* receive channel control */ +#define RC_RE ((uint32)1 << 0) /* receive enable */ +#define RC_RO_MASK 0xfe /* receive frame offset */ +#define RC_RO_SHIFT 1 +#define RC_FM ((uint32)1 << 8) /* direct fifo receive (pio) mode */ +#define RC_AE ((uint32)3 << 16) /* address extension bits */ +#define RC_AE_SHIFT 16 + +/* receive descriptor table pointer */ +#define RP_LD_MASK 0xfff /* last valid descriptor */ + +/* receive channel status */ +#define RS_CD_MASK 0x0fff /* current descriptor pointer */ +#define RS_RS_MASK 0xf000 /* receive state */ +#define RS_RS_SHIFT 12 +#define RS_RS_DISABLED 0x0000 /* disabled */ +#define RS_RS_ACTIVE 0x1000 /* active */ +#define RS_RS_IDLE 0x2000 /* idle wait */ +#define RS_RS_STOPPED 0x3000 /* reserved */ +#define RS_RE_MASK 0xf0000 /* receive errors */ +#define RS_RE_SHIFT 16 +#define RS_RE_NOERR 0x00000 /* no error */ +#define RS_RE_DPE 0x10000 /* descriptor protocol error */ +#define RS_RE_DFO 0x20000 /* data fifo overflow */ +#define RS_RE_BEBW 0x30000 /* bus error on buffer write */ +#define RS_RE_BEDA 0x40000 /* bus error on descriptor access */ +#define RS_AD_MASK 0xfff00000 /* active descriptor */ +#define RS_AD_SHIFT 20 + +/* fifoaddr */ +#define FA_OFF_MASK 0xffff /* offset */ +#define FA_SEL_MASK 0xf0000 /* select */ +#define FA_SEL_SHIFT 16 +#define FA_SEL_XDD 0x00000 /* transmit dma data */ +#define FA_SEL_XDP 0x10000 /* transmit dma pointers */ +#define FA_SEL_RDD 0x40000 /* receive dma data */ +#define FA_SEL_RDP 0x50000 /* receive dma pointers */ +#define FA_SEL_XFD 0x80000 /* transmit fifo data */ +#define FA_SEL_XFP 0x90000 /* transmit fifo pointers */ +#define FA_SEL_RFD 0xc0000 /* receive fifo data */ +#define FA_SEL_RFP 0xd0000 /* receive fifo pointers */ +#define FA_SEL_RSD 0xe0000 /* receive frame status data */ +#define FA_SEL_RSP 0xf0000 /* receive frame status pointers */ + +/* descriptor control flags */ +#define CTRL_BC_MASK 0x1fff /* buffer byte count */ +#define CTRL_AE ((uint32)3 << 16) /* address extension bits */ +#define CTRL_AE_SHIFT 16 +#define CTRL_EOT ((uint32)1 << 28) /* end of descriptor table */ +#define CTRL_IOC ((uint32)1 << 29) /* interrupt on completion */ +#define CTRL_EOF ((uint32)1 << 30) /* end of frame */ +#define CTRL_SOF ((uint32)1 << 31) /* start of frame */ + +/* control flags in the range [27:20] are core-specific and not defined here */ +#define CTRL_CORE_MASK 0x0ff00000 + +/* 64 bits addressing */ + +/* dma registers per channel(xmt or rcv) */ +typedef volatile struct { + uint32 control; /* enable, et al */ + uint32 ptr; /* last descriptor posted to chip */ + uint32 addrlow; /* descriptor ring base address low 32-bits (8K aligned) */ + uint32 addrhigh; /* descriptor ring base address bits 63:32 (8K aligned) */ + uint32 status0; /* current descriptor, xmt state */ + uint32 status1; /* active descriptor, xmt error */ +} dma64regs_t; + +typedef volatile struct { + dma64regs_t tx; /* dma64 tx channel */ + dma64regs_t rx; /* dma64 rx channel */ +} dma64regp_t; + +typedef volatile struct { /* diag access */ + uint32 fifoaddr; /* diag address */ + uint32 fifodatalow; /* low 32bits of data */ + uint32 fifodatahigh; /* high 32bits of data */ + uint32 pad; /* reserved */ +} dma64diag_t; + +/* + * DMA Descriptor + * Descriptors are only read by the hardware, never written back. + */ +typedef volatile struct { + uint32 ctrl1; /* misc control bits & bufcount */ + uint32 ctrl2; /* buffer count and address extension */ + uint32 addrlow; /* memory address of the date buffer, bits 31:0 */ + uint32 addrhigh; /* memory address of the date buffer, bits 63:32 */ +} dma64dd_t; + +/* + * Each descriptor ring must be 8kB aligned, and fit within a contiguous 8kB physical addresss. + */ +#define D64MAXRINGSZ 8192 +#define D64RINGALIGN 8192 +#define D64MAXDD (D64MAXRINGSZ / sizeof (dma64dd_t)) + +/* transmit channel control */ +#define D64_XC_XE 0x00000001 /* transmit enable */ +#define D64_XC_SE 0x00000002 /* transmit suspend request */ +#define D64_XC_LE 0x00000004 /* loopback enable */ +#define D64_XC_FL 0x00000010 /* flush request */ +#define D64_XC_AE 0x00030000 /* address extension bits */ +#define D64_XC_AE_SHIFT 16 + +/* transmit descriptor table pointer */ +#define D64_XP_LD_MASK 0x00000fff /* last valid descriptor */ + +/* transmit channel status */ +#define D64_XS0_CD_MASK 0x00001fff /* current descriptor pointer */ +#define D64_XS0_XS_MASK 0xf0000000 /* transmit state */ +#define D64_XS0_XS_SHIFT 28 +#define D64_XS0_XS_DISABLED 0x00000000 /* disabled */ +#define D64_XS0_XS_ACTIVE 0x10000000 /* active */ +#define D64_XS0_XS_IDLE 0x20000000 /* idle wait */ +#define D64_XS0_XS_STOPPED 0x30000000 /* stopped */ +#define D64_XS0_XS_SUSP 0x40000000 /* suspend pending */ + +#define D64_XS1_AD_MASK 0x0001ffff /* active descriptor */ +#define D64_XS1_XE_MASK 0xf0000000 /* transmit errors */ +#define D64_XS1_XE_SHIFT 28 +#define D64_XS1_XE_NOERR 0x00000000 /* no error */ +#define D64_XS1_XE_DPE 0x10000000 /* descriptor protocol error */ +#define D64_XS1_XE_DFU 0x20000000 /* data fifo underrun */ +#define D64_XS1_XE_DTE 0x30000000 /* data transfer error */ +#define D64_XS1_XE_DESRE 0x40000000 /* descriptor read error */ +#define D64_XS1_XE_COREE 0x50000000 /* core error */ + +/* receive channel control */ +#define D64_RC_RE 0x00000001 /* receive enable */ +#define D64_RC_RO_MASK 0x000000fe /* receive frame offset */ +#define D64_RC_RO_SHIFT 1 +#define D64_RC_FM 0x00000100 /* direct fifo receive (pio) mode */ +#define D64_RC_AE 0x00030000 /* address extension bits */ +#define D64_RC_AE_SHIFT 16 + +/* receive descriptor table pointer */ +#define D64_RP_LD_MASK 0x00000fff /* last valid descriptor */ + +/* receive channel status */ +#define D64_RS0_CD_MASK 0x00001fff /* current descriptor pointer */ +#define D64_RS0_RS_MASK 0xf0000000 /* receive state */ +#define D64_RS0_RS_SHIFT 28 +#define D64_RS0_RS_DISABLED 0x00000000 /* disabled */ +#define D64_RS0_RS_ACTIVE 0x10000000 /* active */ +#define D64_RS0_RS_IDLE 0x20000000 /* idle wait */ +#define D64_RS0_RS_STOPPED 0x30000000 /* stopped */ +#define D64_RS0_RS_SUSP 0x40000000 /* suspend pending */ + +#define D64_RS1_AD_MASK 0x0001ffff /* active descriptor */ +#define D64_RS1_RE_MASK 0xf0000000 /* receive errors */ +#define D64_RS1_RE_SHIFT 28 +#define D64_RS1_RE_NOERR 0x00000000 /* no error */ +#define D64_RS1_RE_DPO 0x10000000 /* descriptor protocol error */ +#define D64_RS1_RE_DFU 0x20000000 /* data fifo overflow */ +#define D64_RS1_RE_DTE 0x30000000 /* data transfer error */ +#define D64_RS1_RE_DESRE 0x40000000 /* descriptor read error */ +#define D64_RS1_RE_COREE 0x50000000 /* core error */ + +/* fifoaddr */ +#define D64_FA_OFF_MASK 0xffff /* offset */ +#define D64_FA_SEL_MASK 0xf0000 /* select */ +#define D64_FA_SEL_SHIFT 16 +#define D64_FA_SEL_XDD 0x00000 /* transmit dma data */ +#define D64_FA_SEL_XDP 0x10000 /* transmit dma pointers */ +#define D64_FA_SEL_RDD 0x40000 /* receive dma data */ +#define D64_FA_SEL_RDP 0x50000 /* receive dma pointers */ +#define D64_FA_SEL_XFD 0x80000 /* transmit fifo data */ +#define D64_FA_SEL_XFP 0x90000 /* transmit fifo pointers */ +#define D64_FA_SEL_RFD 0xc0000 /* receive fifo data */ +#define D64_FA_SEL_RFP 0xd0000 /* receive fifo pointers */ +#define D64_FA_SEL_RSD 0xe0000 /* receive frame status data */ +#define D64_FA_SEL_RSP 0xf0000 /* receive frame status pointers */ + +/* descriptor control flags 1 */ +#define D64_CTRL1_EOT ((uint32)1 << 28) /* end of descriptor table */ +#define D64_CTRL1_IOC ((uint32)1 << 29) /* interrupt on completion */ +#define D64_CTRL1_EOF ((uint32)1 << 30) /* end of frame */ +#define D64_CTRL1_SOF ((uint32)1 << 31) /* start of frame */ + +/* descriptor control flags 2 */ +#define D64_CTRL2_BC_MASK 0x00007fff /* buffer byte count mask */ +#define D64_CTRL2_AE 0x00030000 /* address extension bits */ +#define D64_CTRL2_AE_SHIFT 16 + +/* control flags in the range [27:20] are core-specific and not defined here */ +#define D64_CTRL_CORE_MASK 0x0ff00000 + + +#endif /* _sbhnddma_h_ */ diff --git a/openwrt/package/wlc/src/Makefile b/openwrt/package/broadcom-wl/src/wlc/Makefile similarity index 100% rename from openwrt/package/wlc/src/Makefile rename to openwrt/package/broadcom-wl/src/wlc/Makefile diff --git a/openwrt/package/wlc/src/include/bcmdefs.h b/openwrt/package/broadcom-wl/src/wlc/include/bcmdefs.h similarity index 100% rename from openwrt/package/wlc/src/include/bcmdefs.h rename to openwrt/package/broadcom-wl/src/wlc/include/bcmdefs.h diff --git a/openwrt/package/wlc/src/include/bcmutils.h b/openwrt/package/broadcom-wl/src/wlc/include/bcmutils.h similarity index 100% rename from openwrt/package/wlc/src/include/bcmutils.h rename to openwrt/package/broadcom-wl/src/wlc/include/bcmutils.h diff --git a/openwrt/package/wlc/src/include/proto/802.11.h b/openwrt/package/broadcom-wl/src/wlc/include/proto/802.11.h similarity index 100% rename from openwrt/package/wlc/src/include/proto/802.11.h rename to openwrt/package/broadcom-wl/src/wlc/include/proto/802.11.h diff --git a/openwrt/package/wlc/src/include/proto/bcmeth.h b/openwrt/package/broadcom-wl/src/wlc/include/proto/bcmeth.h similarity index 100% rename from openwrt/package/wlc/src/include/proto/bcmeth.h rename to openwrt/package/broadcom-wl/src/wlc/include/proto/bcmeth.h diff --git a/openwrt/package/wlc/src/include/proto/bcmevent.h b/openwrt/package/broadcom-wl/src/wlc/include/proto/bcmevent.h similarity index 100% rename from openwrt/package/wlc/src/include/proto/bcmevent.h rename to openwrt/package/broadcom-wl/src/wlc/include/proto/bcmevent.h diff --git a/openwrt/package/wlc/src/include/proto/ethernet.h b/openwrt/package/broadcom-wl/src/wlc/include/proto/ethernet.h similarity index 100% rename from openwrt/package/wlc/src/include/proto/ethernet.h rename to openwrt/package/broadcom-wl/src/wlc/include/proto/ethernet.h diff --git a/openwrt/package/wlc/src/include/proto/wpa.h b/openwrt/package/broadcom-wl/src/wlc/include/proto/wpa.h similarity index 100% rename from openwrt/package/wlc/src/include/proto/wpa.h rename to openwrt/package/broadcom-wl/src/wlc/include/proto/wpa.h diff --git a/openwrt/package/wlc/src/include/typedefs.h b/openwrt/package/broadcom-wl/src/wlc/include/typedefs.h similarity index 100% rename from openwrt/package/wlc/src/include/typedefs.h rename to openwrt/package/broadcom-wl/src/wlc/include/typedefs.h diff --git a/openwrt/package/wlc/src/include/wlioctl.h b/openwrt/package/broadcom-wl/src/wlc/include/wlioctl.h similarity index 100% rename from openwrt/package/wlc/src/include/wlioctl.h rename to openwrt/package/broadcom-wl/src/wlc/include/wlioctl.h diff --git a/openwrt/package/wlc/src/include/wlutils.h b/openwrt/package/broadcom-wl/src/wlc/include/wlutils.h similarity index 100% rename from openwrt/package/wlc/src/include/wlutils.h rename to openwrt/package/broadcom-wl/src/wlc/include/wlutils.h diff --git a/openwrt/package/wlc/src/ioctl.c b/openwrt/package/broadcom-wl/src/wlc/ioctl.c similarity index 100% rename from openwrt/package/wlc/src/ioctl.c rename to openwrt/package/broadcom-wl/src/wlc/ioctl.c diff --git a/openwrt/package/wlc/src/wlc.c b/openwrt/package/broadcom-wl/src/wlc/wlc.c similarity index 100% rename from openwrt/package/wlc/src/wlc.c rename to openwrt/package/broadcom-wl/src/wlc/wlc.c diff --git a/openwrt/package/wlc/Makefile b/openwrt/package/wlc/Makefile deleted file mode 100644 index e40fcd8d15..0000000000 --- a/openwrt/package/wlc/Makefile +++ /dev/null @@ -1,40 +0,0 @@ -# $Id: Makefile 2480 2005-11-14 02:07:33Z nbd $ - -include $(TOPDIR)/rules.mk - -PKG_NAME:=wlc -PKG_RELEASE:=1 - -PKG_BUILD_DIR:=$(BUILD_DIR)/wlc - -include $(TOPDIR)/package/rules.mk - -define Package/wlc -SECTION:=base -CATEGORY:=Base system -DEPENDS:=@PACKAGE_KMOD_BRCM_WL -DEFAULT:=y -TITLE:=Utility for configuring the Broadcom wl driver -DESCRIPTION:=Utility for configuring the Broadcom wl driver -endef - - -define Build/Prepare - mkdir -p $(PKG_BUILD_DIR) - $(CP) src/* $(PKG_BUILD_DIR)/ -endef - -define Build/Compile - $(MAKE) -C $(PKG_BUILD_DIR)\ - $(TARGET_CONFIGURE_OPTS) \ - CC="$(TARGET_CC)" \ - CFLAGS="-I$(PKG_BUILD_DIR)/include $(TARGET_CFLAGS)" \ - all -endef - -define Package/wlc/install - install -d -m0755 $(1)/sbin - install -m0755 $(PKG_BUILD_DIR)/wlc $(1)/sbin/ -endef - -$(eval $(call BuildPackage,wlc)) diff --git a/openwrt/target/linux/brcm-2.4/Config.in b/openwrt/target/linux/brcm-2.4/Config.in deleted file mode 100644 index c766a45c3d..0000000000 --- a/openwrt/target/linux/brcm-2.4/Config.in +++ /dev/null @@ -1,8 +0,0 @@ -config PACKAGE_KMOD_BRCM_WL - prompt "kmod-brcm-wl...................... Broadcom Wireless Network Driver" - tristate - depends LINUX_2_4_BRCM - default y - help - Proprietary driver for Broadcom Wireless chipsets - diff --git a/openwrt/target/linux/brcm-2.4/Makefile b/openwrt/target/linux/brcm-2.4/Makefile index 384a1ea918..022f3352c5 100644 --- a/openwrt/target/linux/brcm-2.4/Makefile +++ b/openwrt/target/linux/brcm-2.4/Makefile @@ -8,10 +8,6 @@ include ../rules.mk include ./config # broadcom specific kmod packages -$(eval $(call KMOD_template,BRCM_WL,brcm-wl,\ - $(MODULES_DIR)/kernel/drivers/net/wl/wl.o \ -,CONFIG_WL,,20,wl)) - $(eval $(call KMOD_template,LP,lp,\ $(MODULES_DIR)/kernel/drivers/parport/parport.o \ $(MODULES_DIR)/kernel/drivers/parport/parport_splink.o \ @@ -29,38 +25,3 @@ $(LINUX_DIR)/.patched: $(LINUX_DIR)/.unpacked @$(CP) config $(LINUX_DIR)/.config touch $@ - -############################################### -# Proprietary driver for BCM43xx -############################################### - -LINUX_BINARY_DRIVER_SITE=http://downloads.openwrt.org/sources -# proprietary driver, extracted from Linksys GPL sourcetree WRT54GS 4.70.6 -LINUX_BINARY_WL_DRIVER=kernel-binary-wl-0.7.tar.gz -LINUX_BINARY_WL_MD5SUM=ff50130914790cbae9b73a13513da5ee - -$(DL_DIR)/$(LINUX_BINARY_WL_DRIVER): - $(SCRIPT_DIR)/download.pl $(DL_DIR) $(LINUX_BINARY_WL_DRIVER) $(LINUX_BINARY_WL_MD5SUM) $(LINUX_BINARY_DRIVER_SITE) - -$(LINUX_DIR)/.unpacked: $(DL_DIR)/$(LINUX_BINARY_WL_DRIVER) -$(LINUX_DIR)/.depend_done: $(LINUX_DIR)/.drivers-unpacked -$(LINUX_DIR)/.modules_done: $(LINUX_DIR)/.drivers-unpacked -$(STAMP_DIR)/.linux-compile: $(LINUX_DIR)/.drivers-installed - -$(LINUX_DIR)/.drivers-unpacked: $(LINUX_DIR)/.unpacked - -mkdir -p $(BUILD_DIR) - zcat $(DL_DIR)/$(LINUX_BINARY_WL_DRIVER) | tar -C $(BUILD_DIR) $(TAR_OPTIONS) - - # copy binary wlan driver - mkdir -p $(LINUX_DIR)/drivers/net/wl - $(CP) $(BUILD_DIR)/kernel-binary-wl/*.o $(LINUX_DIR)/drivers/net/wl - touch $@ - -$(LINUX_DIR)/.drivers-installed: $(LINUX_DIR)/.modules_done - mkdir -p $(LINUX_BUILD_DIR)/modules/lib/modules/2.4.32/kernel/drivers/net/wl - @-[ -f $(LINUX_BUILD_DIR)/modules/lib/modules/2.4.32/kernel/drivers/net/wl/wl.o ] || $(CP) $(LINUX_DIR)/drivers/net/wl/wl.o $(LINUX_BUILD_DIR)/modules/lib/modules/2.4.32/kernel/drivers/net/wl/ - touch $@ - -linux-dirclean: drivers-clean - -drivers-clean: FORCE - rm -rf $(BUILD_DIR)/kernel-binary-wl diff --git a/openwrt/target/linux/brcm-2.4/config b/openwrt/target/linux/brcm-2.4/config index c4cf5340ea..7185e9f399 100644 --- a/openwrt/target/linux/brcm-2.4/config +++ b/openwrt/target/linux/brcm-2.4/config @@ -91,7 +91,6 @@ CONFIG_PCI=y CONFIG_NONCOHERENT_IO=y CONFIG_NEW_TIME_C=y CONFIG_NEW_IRQ=y -CONFIG_HND=y # CONFIG_MIPS_AU1000 is not set # @@ -726,7 +725,6 @@ CONFIG_SCSI_MULTI_LUN=y # Network device support # CONFIG_NETDEVICES=y -CONFIG_HND=y # # ARCnet devices @@ -832,7 +830,6 @@ CONFIG_NET_RADIO=y # CONFIG_AIRONET4500_PROC is not set # CONFIG_AIRO is not set # CONFIG_HERMES is not set -CONFIG_WL=m # CONFIG_PLX_HERMES is not set # CONFIG_TMD_HERMES is not set # CONFIG_PCI_HERMES is not set diff --git a/openwrt/target/linux/brcm-2.4/patches/001-bcm47xx.patch b/openwrt/target/linux/brcm-2.4/patches/001-bcm47xx.patch index e1bd00bae2..dc0805e599 100644 --- a/openwrt/target/linux/brcm-2.4/patches/001-bcm47xx.patch +++ b/openwrt/target/linux/brcm-2.4/patches/001-bcm47xx.patch @@ -15886,7 +15886,7 @@ diff -urN linux.old/arch/mips/config-shared.in linux.dev/arch/mips/config-shared # Select some configuration options automatically based on user selections. # if [ "$CONFIG_ACER_PICA_61" = "y" ]; then -@@ -554,6 +567,13 @@ +@@ -554,6 +567,12 @@ define_bool CONFIG_SWAP_IO_SPACE_L y define_bool CONFIG_BOOT_ELF32 y fi @@ -15895,7 +15895,6 @@ diff -urN linux.old/arch/mips/config-shared.in linux.dev/arch/mips/config-shared + define_bool CONFIG_NONCOHERENT_IO y + define_bool CONFIG_NEW_TIME_C y + define_bool CONFIG_NEW_IRQ y -+ define_bool CONFIG_HND y +fi if [ "$CONFIG_SNI_RM200_PCI" = "y" ]; then define_bool CONFIG_ARC32 y @@ -16265,18 +16264,6 @@ diff -urN linux.old/drivers/char/serial.c linux.dev/drivers/char/serial.c cval = cflag & (CSIZE | CSTOPB); #if defined(__powerpc__) || defined(__alpha__) cval >>= 8; -diff -urN linux.old/drivers/net/Config.in linux.dev/drivers/net/Config.in ---- linux.old/drivers/net/Config.in 2006-04-27 18:04:38.000000000 +0200 -+++ linux.dev/drivers/net/Config.in 2006-04-27 19:24:19.000000000 +0200 -@@ -2,6 +2,8 @@ - # Network device configuration - # - -+tristate 'Broadcom Home Network Division' CONFIG_HND $CONFIG_PCI -+ - source drivers/net/arcnet/Config.in - - tristate 'Dummy net driver support' CONFIG_DUMMY diff -urN linux.old/drivers/net/Makefile linux.dev/drivers/net/Makefile --- linux.old/drivers/net/Makefile 2006-04-27 18:04:38.000000000 +0200 +++ linux.dev/drivers/net/Makefile 2006-05-04 01:41:03.000000000 +0200 @@ -16289,3243 +16276,6 @@ diff -urN linux.old/drivers/net/Makefile linux.dev/drivers/net/Makefile obj-y := obj-m := obj-n := -@@ -39,6 +41,7 @@ - obj-$(CONFIG_ISDN) += slhc.o - endif - -+subdir-$(CONFIG_WL) += wl - subdir-$(CONFIG_NET_PCMCIA) += pcmcia - subdir-$(CONFIG_NET_WIRELESS) += wireless - subdir-$(CONFIG_TULIP) += tulip -diff -urN linux.old/drivers/net/wireless/Config.in linux.dev/drivers/net/wireless/Config.in ---- linux.old/drivers/net/wireless/Config.in 2006-04-27 18:04:38.000000000 +0200 -+++ linux.dev/drivers/net/wireless/Config.in 2006-05-04 01:42:48.000000000 +0200 -@@ -13,6 +13,7 @@ - fi - - if [ "$CONFIG_PCI" = "y" ]; then -+ dep_tristate ' Proprietary Broadcom BCM43xx 802.11 Wireless support' CONFIG_WL - dep_tristate ' Hermes in PLX9052 based PCI adaptor support (Netgear MA301 etc.) (EXPERIMENTAL)' CONFIG_PLX_HERMES $CONFIG_HERMES $CONFIG_EXPERIMENTAL - dep_tristate ' Hermes in TMD7160/NCP130 based PCI adaptor support (Pheecom WL-PCI etc.) (EXPERIMENTAL)' CONFIG_TMD_HERMES $CONFIG_HERMES $CONFIG_EXPERIMENTAL - dep_tristate ' Prism 2.5 PCI 802.11b adaptor support (EXPERIMENTAL)' CONFIG_PCI_HERMES $CONFIG_HERMES $CONFIG_EXPERIMENTAL -diff -urN linux.old/drivers/net/wl/patchtable.pl linux.dev/drivers/net/wl/patchtable.pl ---- linux.old/drivers/net/wl/patchtable.pl 1970-01-01 01:00:00.000000000 +0100 -+++ linux.dev/drivers/net/wl/patchtable.pl 2006-04-28 01:33:52.000000000 +0200 -@@ -0,0 +1,54 @@ -+#!/usr/bin/perl -+use strict; -+ -+my $TABLE = pack("V", 0xbadc0ded); -+my $TABLE_SIZE = 512; -+my $SLT1 = "\x01\x00\x00\x00"; -+my $SLT2 = "\x02\x00\x00\x00"; -+my $ACKW = "\x03\x00\x00\x00"; -+my $PTABLE_END = "\xff\xff\xff\xff"; -+ -+my $addr = ""; -+my $opcode = ""; -+my $function = ""; -+ -+sub add_entry { -+ my $key = shift; -+ my $value = shift; -+ my $default = shift; -+ -+ $TABLE .= $key; -+ $TABLE .= pack("V", $value); -+ $TABLE .= pack("V", $default); -+} -+ -+while (<>) { -+ $addr = $opcode = ""; -+ /^\w{8}\s*<(.*)>:$/ and $function = $1; -+ /^\s*(\w+):\s*(\w{8})\s*/ and do { -+ $addr = $1; -+ $opcode = $2; -+ }; -+ -+ ($function eq 'wlc_update_slot_timing') and do { -+ # li a2,9 -- short slot time -+ ($opcode eq '24060009') and add_entry($SLT1, hex($addr), hex($opcode)); -+ # li v0,519 -- 510 + short slot time -+ ($opcode eq '24020207') and add_entry($SLT2, hex($addr), hex($opcode)); -+ -+ # li a2,20 -- long slot time -+ ($opcode eq '24060014') and add_entry($SLT1, hex($addr), hex($opcode)); -+ # li v0,530 -- 510 + long slot time -+ ($opcode eq '24020212') and add_entry($SLT2, hex($addr), hex($opcode)); -+ }; -+ ($function eq 'wlc_d11hdrs') and do { -+ # ori s6,s6,0x1 -- ack flag (new) -+ ($opcode eq '36d60001') and add_entry($ACKW, hex($addr), hex($opcode)); -+ # ori s3,s3,0x1 -- ack flag (old) -+ ($opcode eq '36730001') and add_entry($ACKW, hex($addr), hex($opcode)); -+ } -+} -+ -+$TABLE .= $PTABLE_END; -+$TABLE .= ("\x00" x ($TABLE_SIZE - length($TABLE))); -+print $TABLE; -diff -urN linux.old/drivers/net/wl/Makefile linux.dev/drivers/net/wl/Makefile ---- linux.old/drivers/net/wl/Makefile 1970-01-01 01:00:00.000000000 +0100 -+++ linux.dev/drivers/net/wl/Makefile 2006-04-28 01:33:52.000000000 +0200 -@@ -0,0 +1,32 @@ -+# -+# Makefile for the Broadcom wl driver -+# -+# Copyright 2004, Broadcom Corporation -+# All Rights Reserved. -+# -+# THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY -+# KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM -+# SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS -+# FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. -+# -+# $Id: Makefile,v 1.2 2005/03/29 03:32:18 mbm Exp $ -+ -+EXTRA_CFLAGS += -I$(TOPDIR)/arch/mips/bcm947xx/include -DBCMDRIVER -+ -+O_TARGET := wl_link.o -+ -+obj-y := wl_mod.o -+obj-y += bcmutils.o hnddma.o linux_osl.o -+ -+obj-m := $(O_TARGET) -+ -+wl_mod.o: wl_apsta.o -+ sed -e 's,eth%d,wl%d\x00,g' < $< > $@ -+ -+wl.o: wl_link.o -+ $(OBJDUMP) -d $< | perl patchtable.pl > patchtable.bin -+ cat wl_link.o patchtable.bin > $@ -+ -+modules: wl.o -+ -+include $(TOPDIR)/Rules.make -diff -urN linux.old/drivers/net/wl/bcmip.h linux.dev/drivers/net/wl/bcmip.h ---- linux.old/drivers/net/wl/bcmip.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux.dev/drivers/net/wl/bcmip.h 2006-04-28 02:11:28.000000000 +0200 -@@ -0,0 +1,101 @@ -+/* -+ * Copyright 2006, Broadcom Corporation -+ * All Rights Reserved. -+ * -+ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY -+ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM -+ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS -+ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. -+ * -+ * Fundamental constants relating to IP Protocol -+ * -+ * $Id: bcmip.h,v 1.1.1.3 2006/02/27 03:43:16 honor Exp $ -+ */ -+ -+#ifndef _bcmip_h_ -+#define _bcmip_h_ -+ -+/* IPV4 and IPV6 common */ -+#define IP_VER_OFFSET 0x0 /* offset to version field */ -+#define IP_VER_MASK 0xf0 /* version mask */ -+#define IP_VER_SHIFT 4 /* version shift */ -+#define IP_VER_4 4 /* version number for IPV4 */ -+#define IP_VER_6 6 /* version number for IPV6 */ -+ -+#define IP_VER(ip_body) \ -+ ((((uint8 *)(ip_body))[IP_VER_OFFSET] & IP_VER_MASK) >> IP_VER_SHIFT) -+ -+#define IP_PROT_ICMP 0x1 /* ICMP protocol */ -+#define IP_PROT_TCP 0x6 /* TCP protocol */ -+#define IP_PROT_UDP 0x11 /* UDP protocol type */ -+ -+/* IPV4 field offsets */ -+#define IPV4_VER_HL_OFFSET 0 /* version and ihl byte offset */ -+#define IPV4_TOS_OFFSET 1 /* type of service offset */ -+#define IPV4_PROT_OFFSET 9 /* protocol type offset */ -+#define IPV4_CHKSUM_OFFSET 10 /* IP header checksum offset */ -+#define IPV4_SRC_IP_OFFSET 12 /* src IP addr offset */ -+#define IPV4_DEST_IP_OFFSET 16 /* dest IP addr offset */ -+ -+/* IPV4 field decodes */ -+#define IPV4_VER_MASK 0xf0 /* IPV4 version mask */ -+#define IPV4_VER_SHIFT 4 /* IPV4 version shift */ -+ -+#define IPV4_HLEN_MASK 0x0f /* IPV4 header length mask */ -+#define IPV4_HLEN(ipv4_body) (4 * (((uint8 *)(ipv4_body))[IPV4_VER_HL_OFFSET] & IPV4_HLEN_MASK)) -+ -+#define IPV4_ADDR_LEN 4 /* IPV4 address length */ -+ -+#define IPV4_ADDR_NULL(a) ((((uint8 *)(a))[0] | ((uint8 *)(a))[1] | \ -+ ((uint8 *)(a))[2] | ((uint8 *)(a))[3]) == 0) -+ -+#define IPV4_TOS_DSCP_MASK 0xfc /* DiffServ codepoint mask */ -+#define IPV4_TOS_DSCP_SHIFT 2 /* DiffServ codepoint shift */ -+ -+#define IPV4_TOS(ipv4_body) (((uint8 *)(ipv4_body))[IPV4_TOS_OFFSET]) -+ -+#define IPV4_TOS_PREC_MASK 0xe0 /* Historical precedence mask */ -+#define IPV4_TOS_PREC_SHIFT 5 /* Historical precedence shift */ -+ -+#define IPV4_TOS_LOWDELAY 0x10 /* Lowest delay requested */ -+#define IPV4_TOS_THROUGHPUT 0x8 /* Best throughput requested */ -+#define IPV4_TOS_RELIABILITY 0x4 /* Most reliable delivery requested */ -+ -+#define IPV4_PROT(ipv4_body) (((uint8 *)(ipv4_body))[IPV4_PROT_OFFSET]) -+ -+#define IPV4_ADDR_STR_LEN 16 /* Max IP address length in string format */ -+ -+/* IPV6 field offsets */ -+#define IPV6_PAYLOAD_LEN_OFFSET 4 /* payload length offset */ -+#define IPV6_NEXT_HDR_OFFSET 6 /* next header/protocol offset */ -+#define IPV6_HOP_LIMIT_OFFSET 7 /* hop limit offset */ -+#define IPV6_SRC_IP_OFFSET 8 /* src IP addr offset */ -+#define IPV6_DEST_IP_OFFSET 24 /* dst IP addr offset */ -+ -+/* IPV6 field decodes */ -+#define IPV6_TRAFFIC_CLASS(ipv6_body) \ -+ (((((uint8 *)(ipv6_body))[0] & 0x0f) << 4) | \ -+ ((((uint8 *)(ipv6_body))[1] & 0xf0) >> 4)) -+ -+#define IPV6_FLOW_LABEL(ipv6_body) \ -+ (((((uint8 *)(ipv6_body))[1] & 0x0f) << 16) | \ -+ (((uint8 *)(ipv6_body))[2] << 8) | \ -+ (((uint8 *)(ipv6_body))[3])) -+ -+#define IPV6_PAYLOAD_LEN(ipv6_body) \ -+ ((((uint8 *)(ipv6_body))[IPV6_PAYLOAD_LEN_OFFSET + 0] << 8) | \ -+ ((uint8 *)(ipv6_body))[IPV6_PAYLOAD_LEN_OFFSET + 1]) -+ -+#define IPV6_NEXT_HDR(ipv6_body) \ -+ (((uint8 *)(ipv6_body))[IPV6_NEXT_HDR_OFFSET]) -+ -+#define IPV6_PROT(ipv6_body) IPV6_NEXT_HDR(ipv6_body) -+ -+#define IPV6_ADDR_LEN 16 /* IPV6 address length */ -+ -+/* IPV4 TOS or IPV6 Traffic Classifier or 0 */ -+#define IP_TOS(ip_body) \ -+ (IP_VER(ip_body) == IP_VER_4 ? IPV4_TOS(ip_body) : \ -+ IP_VER(ip_body) == IP_VER_6 ? IPV6_TRAFFIC_CLASS(ip_body) : 0) -+ -+#endif /* _bcmip_h_ */ -diff -urN linux.old/drivers/net/wl/bcmutils.c linux.dev/drivers/net/wl/bcmutils.c ---- linux.old/drivers/net/wl/bcmutils.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux.dev/drivers/net/wl/bcmutils.c 2006-04-28 02:27:20.000000000 +0200 -@@ -0,0 +1,857 @@ -+/* -+ * Misc useful OS-independent routines. -+ * -+ * Copyright 2006, Broadcom Corporation -+ * All Rights Reserved. -+ * -+ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY -+ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM -+ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS -+ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. -+ * $Id: bcmutils.c,v 1.1.1.12 2006/02/27 03:43:16 honor Exp $ -+ */ -+ -+#include -+#include -+#include -+#include -+#include "linux_osl.h" -+#include "pktq.h" -+#include -+#include -+#include -+#include -+#include -+#include "bcmip.h" -+ -+#define ETHER_TYPE_8021Q 0x8100 -+#define ETHER_TYPE_IP 0x0800 -+#define VLAN_PRI_SHIFT 13 -+#define VLAN_PRI_MASK 7 -+ -+ -+struct ether_header { -+ uint8 ether_dhost[6]; -+ uint8 ether_shost[6]; -+ uint16 ether_type; -+} __attribute__((packed)); -+ -+ -+struct ethervlan_header { -+ uint8 ether_dhost[6]; -+ uint8 ether_shost[6]; -+ uint16 vlan_type; /* 0x8100 */ -+ uint16 vlan_tag; /* priority, cfi and vid */ -+ uint16 ether_type; -+}; -+ -+/* copy a pkt buffer chain into a buffer */ -+uint -+pktcopy(osl_t *osh, void *p, uint offset, int len, uchar *buf) -+{ -+ uint n, ret = 0; -+ -+ if (len < 0) -+ len = 4096; /* "infinite" */ -+ -+ /* skip 'offset' bytes */ -+ for (; p && offset; p = PKTNEXT(osh, p)) { -+ if (offset < (uint)PKTLEN(osh, p)) -+ break; -+ offset -= PKTLEN(osh, p); -+ } -+ -+ if (!p) -+ return 0; -+ -+ /* copy the data */ -+ for (; p && len; p = PKTNEXT(osh, p)) { -+ n = MIN((uint)PKTLEN(osh, p) - offset, (uint)len); -+ bcopy(PKTDATA(osh, p) + offset, buf, n); -+ buf += n; -+ len -= n; -+ ret += n; -+ offset = 0; -+ } -+ -+ return ret; -+} -+ -+/* return total length of buffer chain */ -+uint -+pkttotlen(osl_t *osh, void *p) -+{ -+ uint total; -+ -+ total = 0; -+ for (; p; p = PKTNEXT(osh, p)) -+ total += PKTLEN(osh, p); -+ return (total); -+} -+ -+/* return the last buffer of chained pkt */ -+void * -+pktlast(osl_t *osh, void *p) -+{ -+ for (; PKTNEXT(osh, p); p = PKTNEXT(osh, p)) -+ ; -+ -+ return (p); -+} -+ -+ -+/* -+ * osl multiple-precedence packet queue -+ * hi_prec is always >= the number of the highest non-empty queue -+ */ -+void * -+pktq_penq(struct pktq *pq, int prec, void *p) -+{ -+ struct pktq_prec *q; -+ -+ ASSERT(prec >= 0 && prec < pq->num_prec); -+ ASSERT(PKTLINK(p) == NULL); /* queueing chains not allowed */ -+ -+ ASSERT(!pktq_full(pq)); -+ ASSERT(!pktq_pfull(pq, prec)); -+ -+ q = &pq->q[prec]; -+ -+ if (q->head) -+ PKTSETLINK(q->tail, p); -+ else -+ q->head = p; -+ -+ q->tail = p; -+ q->len++; -+ -+ pq->len++; -+ -+ if (pq->hi_prec < prec) -+ pq->hi_prec = (uint8)prec; -+ -+ return p; -+} -+ -+void * -+pktq_penq_head(struct pktq *pq, int prec, void *p) -+{ -+ struct pktq_prec *q; -+ -+ ASSERT(prec >= 0 && prec < pq->num_prec); -+ ASSERT(PKTLINK(p) == NULL); /* queueing chains not allowed */ -+ -+ ASSERT(!pktq_full(pq)); -+ ASSERT(!pktq_pfull(pq, prec)); -+ -+ q = &pq->q[prec]; -+ -+ if (q->head == NULL) -+ q->tail = p; -+ -+ PKTSETLINK(p, q->head); -+ q->head = p; -+ q->len++; -+ -+ pq->len++; -+ -+ if (pq->hi_prec < prec) -+ pq->hi_prec = (uint8)prec; -+ -+ return p; -+} -+ -+void * -+pktq_pdeq(struct pktq *pq, int prec) -+{ -+ struct pktq_prec *q; -+ void *p; -+ -+ ASSERT(prec >= 0 && prec < pq->num_prec); -+ -+ q = &pq->q[prec]; -+ -+ if ((p = q->head) == NULL) -+ return NULL; -+ -+ if ((q->head = PKTLINK(p)) == NULL) -+ q->tail = NULL; -+ -+ q->len--; -+ -+ pq->len--; -+ -+ PKTSETLINK(p, NULL); -+ -+ return p; -+} -+ -+void * -+pktq_pdeq_tail(struct pktq *pq, int prec) -+{ -+ struct pktq_prec *q; -+ void *p, *prev; -+ -+ ASSERT(prec >= 0 && prec < pq->num_prec); -+ -+ q = &pq->q[prec]; -+ -+ if ((p = q->head) == NULL) -+ return NULL; -+ -+ for (prev = NULL; p != q->tail; p = PKTLINK(p)) -+ prev = p; -+ -+ if (prev) -+ PKTSETLINK(prev, NULL); -+ else -+ q->head = NULL; -+ -+ q->tail = prev; -+ q->len--; -+ -+ pq->len--; -+ -+ return p; -+} -+ -+void -+pktq_pflush(osl_t *osh, struct pktq *pq, int prec, bool dir) -+{ -+ struct pktq_prec *q; -+ void *p; -+ -+ q = &pq->q[prec]; -+ p = q->head; -+ while (p) { -+ q->head = PKTLINK(p); -+ PKTSETLINK(p, NULL); -+ PKTFREE(osh, p, dir); -+ q->len--; -+ pq->len--; -+ p = q->head; -+ } -+ ASSERT(q->len == 0); -+ q->tail = NULL; -+} -+ -+bool -+pktq_pdel(struct pktq *pq, void *pktbuf, int prec) -+{ -+ struct pktq_prec *q; -+ void *p; -+ -+ ASSERT(prec >= 0 && prec < pq->num_prec); -+ -+ if (!pktbuf) -+ return FALSE; -+ -+ q = &pq->q[prec]; -+ -+ if (q->head == pktbuf) { -+ if ((q->head = PKTLINK(pktbuf)) == NULL) -+ q->tail = NULL; -+ } else { -+ for (p = q->head; p && PKTLINK(p) != pktbuf; p = PKTLINK(p)) -+ ; -+ if (p == NULL) -+ return FALSE; -+ -+ PKTSETLINK(p, PKTLINK(pktbuf)); -+ if (q->tail == pktbuf) -+ q->tail = p; -+ } -+ -+ q->len--; -+ pq->len--; -+ PKTSETLINK(pktbuf, NULL); -+ return TRUE; -+} -+ -+void -+pktq_init(struct pktq *pq, int num_prec, int max_len) -+{ -+ int prec; -+ -+ ASSERT(num_prec > 0 && num_prec <= PKTQ_MAX_PREC); -+ -+ bzero(pq, sizeof(*pq)); -+ -+ pq->num_prec = (uint16)num_prec; -+ -+ pq->max = (uint16)max_len; -+ -+ for (prec = 0; prec < num_prec; prec++) -+ pq->q[prec].max = pq->max; -+} -+ -+void * -+pktq_deq(struct pktq *pq, int *prec_out) -+{ -+ struct pktq_prec *q; -+ void *p; -+ int prec; -+ -+ if (pq->len == 0) -+ return NULL; -+ -+ while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL) -+ pq->hi_prec--; -+ -+ q = &pq->q[prec]; -+ -+ if ((p = q->head) == NULL) -+ return NULL; -+ -+ if ((q->head = PKTLINK(p)) == NULL) -+ q->tail = NULL; -+ -+ q->len--; -+ -+ pq->len--; -+ -+ if (prec_out) -+ *prec_out = prec; -+ -+ PKTSETLINK(p, NULL); -+ -+ return p; -+} -+ -+void * -+pktq_deq_tail(struct pktq *pq, int *prec_out) -+{ -+ struct pktq_prec *q; -+ void *p, *prev; -+ int prec; -+ -+ if (pq->len == 0) -+ return NULL; -+ -+ for (prec = 0; prec < pq->hi_prec; prec++) -+ if (pq->q[prec].head) -+ break; -+ -+ q = &pq->q[prec]; -+ -+ if ((p = q->head) == NULL) -+ return NULL; -+ -+ for (prev = NULL; p != q->tail; p = PKTLINK(p)) -+ prev = p; -+ -+ if (prev) -+ PKTSETLINK(prev, NULL); -+ else -+ q->head = NULL; -+ -+ q->tail = prev; -+ q->len--; -+ -+ pq->len--; -+ -+ if (prec_out) -+ *prec_out = prec; -+ -+ PKTSETLINK(p, NULL); -+ -+ return p; -+} -+ -+void * -+pktq_peek(struct pktq *pq, int *prec_out) -+{ -+ int prec; -+ -+ if (pq->len == 0) -+ return NULL; -+ -+ while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL) -+ pq->hi_prec--; -+ -+ if (prec_out) -+ *prec_out = prec; -+ -+ return (pq->q[prec].head); -+} -+ -+void * -+pktq_peek_tail(struct pktq *pq, int *prec_out) -+{ -+ int prec; -+ -+ if (pq->len == 0) -+ return NULL; -+ -+ for (prec = 0; prec < pq->hi_prec; prec++) -+ if (pq->q[prec].head) -+ break; -+ -+ if (prec_out) -+ *prec_out = prec; -+ -+ return (pq->q[prec].tail); -+} -+ -+void -+pktq_flush(osl_t *osh, struct pktq *pq, bool dir) -+{ -+ int prec; -+ for (prec = 0; prec < pq->num_prec; prec++) -+ pktq_pflush(osh, pq, prec, dir); -+ ASSERT(pq->len == 0); -+} -+ -+/* Return sum of lengths of a specific set of precedences */ -+int -+pktq_mlen(struct pktq *pq, uint prec_bmp) -+{ -+ int prec, len; -+ -+ len = 0; -+ -+ for (prec = 0; prec <= pq->hi_prec; prec++) -+ if (prec_bmp & (1 << prec)) -+ len += pq->q[prec].len; -+ -+ return len; -+} -+ -+/* Priority dequeue from a specific set of precedences */ -+void * -+pktq_mdeq(struct pktq *pq, uint prec_bmp, int *prec_out) -+{ -+ struct pktq_prec *q; -+ void *p; -+ int prec; -+ -+ if (pq->len == 0) -+ return NULL; -+ -+ while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL) -+ pq->hi_prec--; -+ -+ while ((prec_bmp & (1 << prec)) == 0 || pq->q[prec].head == NULL) -+ if (prec-- == 0) -+ return NULL; -+ -+ q = &pq->q[prec]; -+ -+ if ((p = q->head) == NULL) -+ return NULL; -+ -+ if ((q->head = PKTLINK(p)) == NULL) -+ q->tail = NULL; -+ -+ q->len--; -+ -+ if (prec_out) -+ *prec_out = prec; -+ -+ pq->len--; -+ -+ PKTSETLINK(p, NULL); -+ -+ return p; -+} -+ -+char* -+bcmstrcat(char *dest, const char *src) -+{ -+ strcpy(&dest[strlen(dest)], src); -+ return (dest); -+} -+ -+char* -+bcm_ether_ntoa(struct ether_addr *ea, char *buf) -+{ -+ sprintf(buf, "%02x:%02x:%02x:%02x:%02x:%02x", -+ ea->octet[0]&0xff, ea->octet[1]&0xff, ea->octet[2]&0xff, -+ ea->octet[3]&0xff, ea->octet[4]&0xff, ea->octet[5]&0xff); -+ return (buf); -+} -+ -+/* parse a xx:xx:xx:xx:xx:xx format ethernet address */ -+int -+bcm_ether_atoe(char *p, struct ether_addr *ea) -+{ -+ int i = 0; -+ -+ for (;;) { -+ ea->octet[i++] = (char) bcm_strtoul(p, &p, 16); -+ if (!*p++ || i == 6) -+ break; -+ } -+ -+ return (i == 6); -+} -+ -+/* Takes an Ethernet frame and sets out-of-bound PKTPRIO -+ * Also updates the inplace vlan tag if requested -+ */ -+void -+pktsetprio(void *pkt, bool update_vtag) -+{ -+ struct ether_header *eh; -+ struct ethervlan_header *evh; -+ uint8 *pktdata; -+ int priority = 0; -+ -+ pktdata = (uint8 *) PKTDATA(NULL, pkt); -+ ASSERT(ISALIGNED((uintptr)pktdata, sizeof(uint16))); -+ -+ eh = (struct ether_header *) pktdata; -+ -+ if (ntoh16(eh->ether_type) == ETHER_TYPE_8021Q) { -+ uint16 vlan_tag; -+ int vlan_prio, dscp_prio = 0; -+ -+ evh = (struct ethervlan_header *)eh; -+ -+ vlan_tag = ntoh16(evh->vlan_tag); -+ vlan_prio = (int) (vlan_tag >> VLAN_PRI_SHIFT) & VLAN_PRI_MASK; -+ -+ if (ntoh16(evh->ether_type) == ETHER_TYPE_IP) { -+ uint8 *ip_body = pktdata + sizeof(struct ethervlan_header); -+ uint8 tos_tc = IP_TOS(ip_body); -+ dscp_prio = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT); -+ } -+ -+ /* DSCP priority gets precedence over 802.1P (vlan tag) */ -+ priority = (dscp_prio != 0) ? dscp_prio : vlan_prio; -+ -+ /* -+ * If the DSCP priority is not the same as the VLAN priority, -+ * then overwrite the priority field in the vlan tag, with the -+ * DSCP priority value. This is required for Linux APs because -+ * the VLAN driver on Linux, overwrites the skb->priority field -+ * with the priority value in the vlan tag -+ */ -+ if (update_vtag && (priority != vlan_prio)) { -+ vlan_tag &= ~(VLAN_PRI_MASK << VLAN_PRI_SHIFT); -+ vlan_tag |= (uint16)priority << VLAN_PRI_SHIFT; -+ evh->vlan_tag = hton16(vlan_tag); -+ } -+ } else if (ntoh16(eh->ether_type) == ETHER_TYPE_IP) { -+ uint8 *ip_body = pktdata + sizeof(struct ether_header); -+ uint8 tos_tc = IP_TOS(ip_body); -+ priority = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT); -+ } -+ -+ ASSERT(priority >= 0 && priority <= MAXPRIO); -+ PKTSETPRIO(pkt, priority); -+} -+ -+static char bcm_undeferrstr[BCME_STRLEN]; -+ -+static const char *bcmerrorstrtable[] = BCMERRSTRINGTABLE; -+ -+/* Convert the Error codes into related Error strings */ -+const char * -+bcmerrorstr(int bcmerror) -+{ -+ int abs_bcmerror; -+ -+ abs_bcmerror = ABS(bcmerror); -+ -+ /* check if someone added a bcmerror code but forgot to add errorstring */ -+ ASSERT(ABS(BCME_LAST) == (ARRAYSIZE(bcmerrorstrtable) - 1)); -+ if ((bcmerror > 0) || (abs_bcmerror > ABS(BCME_LAST))) { -+ sprintf(bcm_undeferrstr, "undefined Error %d", bcmerror); -+ return bcm_undeferrstr; -+ } -+ -+ ASSERT((strlen((char*)bcmerrorstrtable[abs_bcmerror])) < BCME_STRLEN); -+ -+ return bcmerrorstrtable[abs_bcmerror]; -+} -+ -+ -+int -+bcm_iovar_lencheck(const bcm_iovar_t *vi, void *arg, int len, bool set) -+{ -+ int bcmerror = 0; -+ -+ /* length check on io buf */ -+ switch (vi->type) { -+ case IOVT_BOOL: -+ case IOVT_INT8: -+ case IOVT_INT16: -+ case IOVT_INT32: -+ case IOVT_UINT8: -+ case IOVT_UINT16: -+ case IOVT_UINT32: -+ /* all integers are int32 sized args at the ioctl interface */ -+ if (len < (int)sizeof(int)) { -+ bcmerror = BCME_BUFTOOSHORT; -+ } -+ break; -+ -+ case IOVT_BUFFER: -+ /* buffer must meet minimum length requirement */ -+ if (len < vi->minlen) { -+ bcmerror = BCME_BUFTOOSHORT; -+ } -+ break; -+ -+ case IOVT_VOID: -+ if (!set) { -+ /* Cannot return nil... */ -+ bcmerror = BCME_UNSUPPORTED; -+ } else if (len) { -+ /* Set is an action w/o parameters */ -+ bcmerror = BCME_BUFTOOLONG; -+ } -+ break; -+ -+ default: -+ /* unknown type for length check in iovar info */ -+ ASSERT(0); -+ bcmerror = BCME_UNSUPPORTED; -+ } -+ -+ return bcmerror; -+} -+ -+#define CRC_INNER_LOOP(n, c, x) \ -+ (c) = ((c) >> 8) ^ crc##n##_table[((c) ^ (x)) & 0xff] -+ -+static uint32 crc32_table[256] = { -+ 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, -+ 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, -+ 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, -+ 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, -+ 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, -+ 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, -+ 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, -+ 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, -+ 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, -+ 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, -+ 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, -+ 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, -+ 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, -+ 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, -+ 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, -+ 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, -+ 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, -+ 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, -+ 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, -+ 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, -+ 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, -+ 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, -+ 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, -+ 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, -+ 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, -+ 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, -+ 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, -+ 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, -+ 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, -+ 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, -+ 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, -+ 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, -+ 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, -+ 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, -+ 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, -+ 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, -+ 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, -+ 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, -+ 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, -+ 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, -+ 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, -+ 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, -+ 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, -+ 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, -+ 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, -+ 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, -+ 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, -+ 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, -+ 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, -+ 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, -+ 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, -+ 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, -+ 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, -+ 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, -+ 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, -+ 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, -+ 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, -+ 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, -+ 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, -+ 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, -+ 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, -+ 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, -+ 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, -+ 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D -+}; -+ -+uint32 -+hndcrc32( -+ uint8 *pdata, /* pointer to array of data to process */ -+ uint nbytes, /* number of input data bytes to process */ -+ uint32 crc /* either CRC32_INIT_VALUE or previous return value */ -+) -+{ -+ uint8 *pend; -+#ifdef __mips__ -+ uint8 tmp[4]; -+ ulong *tptr = (ulong *)tmp; -+ -+ /* in case the beginning of the buffer isn't aligned */ -+ pend = (uint8 *)((uint)(pdata + 3) & 0xfffffffc); -+ nbytes -= (pend - pdata); -+ while (pdata < pend) -+ CRC_INNER_LOOP(32, crc, *pdata++); -+ -+ /* handle bulk of data as 32-bit words */ -+ pend = pdata + (nbytes & 0xfffffffc); -+ while (pdata < pend) { -+ *tptr = *(ulong *)pdata; -+ pdata += sizeof(ulong *); -+ CRC_INNER_LOOP(32, crc, tmp[0]); -+ CRC_INNER_LOOP(32, crc, tmp[1]); -+ CRC_INNER_LOOP(32, crc, tmp[2]); -+ CRC_INNER_LOOP(32, crc, tmp[3]); -+ } -+ -+ /* 1-3 bytes at end of buffer */ -+ pend = pdata + (nbytes & 0x03); -+ while (pdata < pend) -+ CRC_INNER_LOOP(32, crc, *pdata++); -+#else -+ pend = pdata + nbytes; -+ while (pdata < pend) -+ CRC_INNER_LOOP(32, crc, *pdata++); -+#endif /* __mips__ */ -+ -+ return crc; -+} -+ -+ -+/* -+ * Advance from the current 1-byte tag/1-byte length/variable-length value -+ * triple, to the next, returning a pointer to the next. -+ * If the current or next TLV is invalid (does not fit in given buffer length), -+ * NULL is returned. -+ * *buflen is not modified if the TLV elt parameter is invalid, or is decremented -+ * by the TLV paramter's length if it is valid. -+ */ -+bcm_tlv_t * -+bcm_next_tlv(bcm_tlv_t *elt, int *buflen) -+{ -+ int len; -+ -+ /* validate current elt */ -+ if (!bcm_valid_tlv(elt, *buflen)) -+ return NULL; -+ -+ /* advance to next elt */ -+ len = elt->len; -+ elt = (bcm_tlv_t*)(elt->data + len); -+ *buflen -= (2 + len); -+ -+ /* validate next elt */ -+ if (!bcm_valid_tlv(elt, *buflen)) -+ return NULL; -+ -+ return elt; -+} -+ -+/* -+ * Traverse a string of 1-byte tag/1-byte length/variable-length value -+ * triples, returning a pointer to the substring whose first element -+ * matches tag -+ */ -+bcm_tlv_t * -+bcm_parse_tlvs(void *buf, int buflen, uint key) -+{ -+ bcm_tlv_t *elt; -+ int totlen; -+ -+ elt = (bcm_tlv_t*)buf; -+ totlen = buflen; -+ -+ /* find tagged parameter */ -+ while (totlen >= 2) { -+ int len = elt->len; -+ -+ /* validate remaining totlen */ -+ if ((elt->id == key) && (totlen >= (len + 2))) -+ return (elt); -+ -+ elt = (bcm_tlv_t*)((uint8*)elt + (len + 2)); -+ totlen -= (len + 2); -+ } -+ -+ return NULL; -+} -+ -+/* -+ * Traverse a string of 1-byte tag/1-byte length/variable-length value -+ * triples, returning a pointer to the substring whose first element -+ * matches tag. Stop parsing when we see an element whose ID is greater -+ * than the target key. -+ */ -+bcm_tlv_t * -+bcm_parse_ordered_tlvs(void *buf, int buflen, uint key) -+{ -+ bcm_tlv_t *elt; -+ int totlen; -+ -+ elt = (bcm_tlv_t*)buf; -+ totlen = buflen; -+ -+ /* find tagged parameter */ -+ while (totlen >= 2) { -+ uint id = elt->id; -+ int len = elt->len; -+ -+ /* Punt if we start seeing IDs > than target key */ -+ if (id > key) -+ return (NULL); -+ -+ /* validate remaining totlen */ -+ if ((id == key) && (totlen >= (len + 2))) -+ return (elt); -+ -+ elt = (bcm_tlv_t*)((uint8*)elt + (len + 2)); -+ totlen -= (len + 2); -+ } -+ return NULL; -+} -+ -+ -+/* Initialization of bcmstrbuf structure */ -+void -+bcm_binit(struct bcmstrbuf *b, char *buf, uint size) -+{ -+ b->origsize = b->size = size; -+ b->origbuf = b->buf = buf; -+} -+ -+/* Buffer sprintf wrapper to guard against buffer overflow */ -+int -+bcm_bprintf(struct bcmstrbuf *b, const char *fmt, ...) -+{ -+ va_list ap; -+ int r; -+ -+ va_start(ap, fmt); -+ r = vsnprintf(b->buf, b->size, fmt, ap); -+ -+ /* Non Ansi C99 compliant returns -1, -+ * Ansi compliant return r >= b->size, -+ * bcmstdlib returns 0, handle all -+ */ -+ if ((r == -1) || (r >= (int)b->size) || (r == 0)) -+ { -+ b->size = 0; -+ } -+ else -+ { -+ b->size -= r; -+ b->buf += r; -+ } -+ -+ va_end(ap); -+ -+ return r; -+} -diff -urN linux.old/drivers/net/wl/hnddma.c linux.dev/drivers/net/wl/hnddma.c ---- linux.old/drivers/net/wl/hnddma.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux.dev/drivers/net/wl/hnddma.c 2006-05-02 17:42:13.000000000 +0200 -@@ -0,0 +1,1157 @@ -+/* -+ * Generic Broadcom Home Networking Division (HND) DMA module. -+ * This supports the following chips: BCM42xx, 44xx, 47xx . -+ * -+ * Copyright 2006, Broadcom Corporation -+ * All Rights Reserved. -+ * -+ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY -+ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM -+ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS -+ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. -+ * -+ * $Id: hnddma.c,v 1.11 2006/04/08 07:12:42 honor Exp $ -+ */ -+ -+#include -+#include -+#include -+#include "linux_osl.h" -+#include -+#include -+#include -+#include -+#include -+ -+#include "sbhnddma.h" -+#include "hnddma.h" -+ -+/* debug/trace */ -+#define DMA_ERROR(args) -+#define DMA_TRACE(args) -+ -+/* default dma message level (if input msg_level pointer is null in dma_attach()) */ -+static uint dma_msg_level = -+ 0; -+ -+#define MAXNAMEL 8 /* 8 char names */ -+ -+#define DI_INFO(dmah) (dma_info_t *)dmah -+ -+/* dma engine software state */ -+typedef struct dma_info { -+ struct hnddma_pub hnddma; /* exported structure, don't use hnddma_t, -+ * which could be const -+ */ -+ uint *msg_level; /* message level pointer */ -+ char name[MAXNAMEL]; /* callers name for diag msgs */ -+ -+ void *osh; /* os handle */ -+ sb_t *sbh; /* sb handle */ -+ -+ bool dma64; /* dma64 enabled */ -+ bool addrext; /* this dma engine supports DmaExtendedAddrChanges */ -+ -+ dma32regs_t *d32txregs; /* 32 bits dma tx engine registers */ -+ dma32regs_t *d32rxregs; /* 32 bits dma rx engine registers */ -+ dma64regs_t *d64txregs; /* 64 bits dma tx engine registers */ -+ dma64regs_t *d64rxregs; /* 64 bits dma rx engine registers */ -+ -+ uint32 dma64align; /* either 8k or 4k depends on number of dd */ -+ dma32dd_t *txd32; /* pointer to dma32 tx descriptor ring */ -+ dma64dd_t *txd64; /* pointer to dma64 tx descriptor ring */ -+ uint ntxd; /* # tx descriptors tunable */ -+ uint txin; /* index of next descriptor to reclaim */ -+ uint txout; /* index of next descriptor to post */ -+ void **txp; /* pointer to parallel array of pointers to packets */ -+ osldma_t *tx_dmah; /* DMA TX descriptor ring handle */ -+ osldma_t **txp_dmah; /* DMA TX packet data handle */ -+ ulong txdpa; /* physical address of descriptor ring */ -+ uint txdalign; /* #bytes added to alloc'd mem to align txd */ -+ uint txdalloc; /* #bytes allocated for the ring */ -+ -+ dma32dd_t *rxd32; /* pointer to dma32 rx descriptor ring */ -+ dma64dd_t *rxd64; /* pointer to dma64 rx descriptor ring */ -+ uint nrxd; /* # rx descriptors tunable */ -+ uint rxin; /* index of next descriptor to reclaim */ -+ uint rxout; /* index of next descriptor to post */ -+ void **rxp; /* pointer to parallel array of pointers to packets */ -+ osldma_t *rx_dmah; /* DMA RX descriptor ring handle */ -+ osldma_t **rxp_dmah; /* DMA RX packet data handle */ -+ ulong rxdpa; /* physical address of descriptor ring */ -+ uint rxdalign; /* #bytes added to alloc'd mem to align rxd */ -+ uint rxdalloc; /* #bytes allocated for the ring */ -+ -+ /* tunables */ -+ uint rxbufsize; /* rx buffer size in bytes, -+ not including the extra headroom -+ */ -+ uint nrxpost; /* # rx buffers to keep posted */ -+ uint rxoffset; /* rxcontrol offset */ -+ uint ddoffsetlow; /* add to get dma address of descriptor ring, low 32 bits */ -+ uint ddoffsethigh; /* high 32 bits */ -+ uint dataoffsetlow; /* add to get dma address of data buffer, low 32 bits */ -+ uint dataoffsethigh; /* high 32 bits */ -+} dma_info_t; -+ -+/* descriptor bumping macros */ -+#define XXD(x, n) ((x) & ((n) - 1)) /* faster than %, but n must be power of 2 */ -+#define TXD(x) XXD((x), di->ntxd) -+#define RXD(x) XXD((x), di->nrxd) -+#define NEXTTXD(i) TXD(i + 1) -+#define PREVTXD(i) TXD(i - 1) -+#define NEXTRXD(i) RXD(i + 1) -+#define NTXDACTIVE(h, t) TXD(t - h) -+#define NRXDACTIVE(h, t) RXD(t - h) -+ -+/* macros to convert between byte offsets and indexes */ -+#define B2I(bytes, type) ((bytes) / sizeof(type)) -+#define I2B(index, type) ((index) * sizeof(type)) -+ -+#define PCI32ADDR_HIGH 0xc0000000 /* address[31:30] */ -+#define PCI32ADDR_HIGH_SHIFT 30 /* address[31:30] */ -+ -+ -+/* common prototypes */ -+static bool _dma_isaddrext(dma_info_t *di); -+static bool dma32_alloc(dma_info_t *di, uint direction); -+static void _dma_detach(dma_info_t *di); -+static void _dma_ddtable_init(dma_info_t *di, uint direction, ulong pa); -+static void _dma_rxinit(dma_info_t *di); -+static void *_dma_rx(dma_info_t *di); -+static void _dma_rxfill(dma_info_t *di); -+static void _dma_rxreclaim(dma_info_t *di); -+static void _dma_rxenable(dma_info_t *di); -+static void * _dma_getnextrxp(dma_info_t *di, bool forceall); -+ -+static void _dma_txblock(dma_info_t *di); -+static void _dma_txunblock(dma_info_t *di); -+static uint _dma_txactive(dma_info_t *di); -+ -+static void* _dma_peeknexttxp(dma_info_t *di); -+static uintptr _dma_getvar(dma_info_t *di, char *name); -+static void _dma_counterreset(dma_info_t *di); -+static void _dma_fifoloopbackenable(dma_info_t *di); -+ -+/* ** 32 bit DMA prototypes */ -+static bool dma32_alloc(dma_info_t *di, uint direction); -+static bool dma32_txreset(dma_info_t *di); -+static bool dma32_rxreset(dma_info_t *di); -+static bool dma32_txsuspendedidle(dma_info_t *di); -+static int dma32_txfast(dma_info_t *di, void *p0, bool commit); -+static void *dma32_getnexttxp(dma_info_t *di, bool forceall); -+static void *dma32_getnextrxp(dma_info_t *di, bool forceall); -+static void dma32_txrotate(dma_info_t *di); -+static bool dma32_rxidle(dma_info_t *di); -+static void dma32_txinit(dma_info_t *di); -+static bool dma32_txenabled(dma_info_t *di); -+static void dma32_txsuspend(dma_info_t *di); -+static void dma32_txresume(dma_info_t *di); -+static bool dma32_txsuspended(dma_info_t *di); -+static void dma32_txreclaim(dma_info_t *di, bool forceall); -+static bool dma32_txstopped(dma_info_t *di); -+static bool dma32_rxstopped(dma_info_t *di); -+static bool dma32_rxenabled(dma_info_t *di); -+static bool _dma32_addrext(osl_t *osh, dma32regs_t *dma32regs); -+ -+ -+static di_fcn_t dma32proc = { -+ (di_detach_t)_dma_detach, -+ (di_txinit_t)dma32_txinit, -+ (di_txreset_t)dma32_txreset, -+ (di_txenabled_t)dma32_txenabled, -+ (di_txsuspend_t)dma32_txsuspend, -+ (di_txresume_t)dma32_txresume, -+ (di_txsuspended_t)dma32_txsuspended, -+ (di_txsuspendedidle_t)dma32_txsuspendedidle, -+ (di_txfast_t)dma32_txfast, -+ (di_txstopped_t)dma32_txstopped, -+ (di_txreclaim_t)dma32_txreclaim, -+ (di_getnexttxp_t)dma32_getnexttxp, -+ (di_peeknexttxp_t)_dma_peeknexttxp, -+ (di_txblock_t)_dma_txblock, -+ (di_txunblock_t)_dma_txunblock, -+ (di_txactive_t)_dma_txactive, -+ (di_txrotate_t)dma32_txrotate, -+ -+ (di_rxinit_t)_dma_rxinit, -+ (di_rxreset_t)dma32_rxreset, -+ (di_rxidle_t)dma32_rxidle, -+ (di_rxstopped_t)dma32_rxstopped, -+ (di_rxenable_t)_dma_rxenable, -+ (di_rxenabled_t)dma32_rxenabled, -+ (di_rx_t)_dma_rx, -+ (di_rxfill_t)_dma_rxfill, -+ (di_rxreclaim_t)_dma_rxreclaim, -+ (di_getnextrxp_t)_dma_getnextrxp, -+ -+ (di_fifoloopbackenable_t)_dma_fifoloopbackenable, -+ (di_getvar_t)_dma_getvar, -+ (di_counterreset_t)_dma_counterreset, -+ -+ NULL, -+ NULL, -+ NULL, -+ 34 -+}; -+ -+hnddma_t * -+dma_attach(osl_t *osh, char *name, sb_t *sbh, void *dmaregstx, void *dmaregsrx, -+ uint ntxd, uint nrxd, uint rxbufsize, uint nrxpost, uint rxoffset, uint *msg_level) -+{ -+ dma_info_t *di; -+ uint size; -+ -+ /* allocate private info structure */ -+ if ((di = MALLOC(osh, sizeof (dma_info_t))) == NULL) { -+ return (NULL); -+ } -+ bzero((char *)di, sizeof(dma_info_t)); -+ -+ di->msg_level = msg_level ? msg_level : &dma_msg_level; -+ -+ /* old chips w/o sb is no longer supported */ -+ ASSERT(sbh != NULL); -+ -+ /* check arguments */ -+ ASSERT(ISPOWEROF2(ntxd)); -+ ASSERT(ISPOWEROF2(nrxd)); -+ if (nrxd == 0) -+ ASSERT(dmaregsrx == NULL); -+ if (ntxd == 0) -+ ASSERT(dmaregstx == NULL); -+ -+ -+ /* init dma reg pointer */ -+ ASSERT(ntxd <= D32MAXDD); -+ ASSERT(nrxd <= D32MAXDD); -+ di->d32txregs = (dma32regs_t *)dmaregstx; -+ di->d32rxregs = (dma32regs_t *)dmaregsrx; -+ -+ DMA_TRACE(("%s: dma_attach: %s osh %p ntxd %d nrxd %d rxbufsize %d nrxpost %d " -+ "rxoffset %d dmaregstx %p dmaregsrx %p\n", -+ name, "DMA32", osh, ntxd, nrxd, rxbufsize, -+ nrxpost, rxoffset, dmaregstx, dmaregsrx)); -+ -+ /* make a private copy of our callers name */ -+ strncpy(di->name, name, MAXNAMEL); -+ di->name[MAXNAMEL-1] = '\0'; -+ -+ di->osh = osh; -+ di->sbh = sbh; -+ -+ /* save tunables */ -+ di->ntxd = ntxd; -+ di->nrxd = nrxd; -+ -+ /* the actual dma size doesn't include the extra headroom */ -+ if (rxbufsize > BCMEXTRAHDROOM) -+ di->rxbufsize = rxbufsize - BCMEXTRAHDROOM; -+ else -+ di->rxbufsize = rxbufsize; -+ -+ di->nrxpost = nrxpost; -+ di->rxoffset = rxoffset; -+ -+ /* -+ * figure out the DMA physical address offset for dd and data -+ * for old chips w/o sb, use zero -+ * for new chips w sb, -+ * PCI/PCIE: they map silicon backplace address to zero based memory, need offset -+ * Other bus: use zero -+ * SB_BUS BIGENDIAN kludge: use sdram swapped region for data buffer, not descriptor -+ */ -+ di->ddoffsetlow = 0; -+ di->dataoffsetlow = 0; -+ /* for pci bus, add offset */ -+ if (sbh->bustype == PCI_BUS) { -+ di->ddoffsetlow = SB_PCI_DMA; -+ di->ddoffsethigh = 0; -+ di->dataoffsetlow = di->ddoffsetlow; -+ di->dataoffsethigh = di->ddoffsethigh; -+ } -+ -+#if defined(__mips__) && defined(IL_BIGENDIAN) -+ di->dataoffsetlow = di->dataoffsetlow + SB_SDRAM_SWAPPED; -+#endif -+ -+ di->addrext = _dma_isaddrext(di); -+ -+ /* allocate tx packet pointer vector */ -+ if (ntxd) { -+ size = ntxd * sizeof(void *); -+ if ((di->txp = MALLOC(osh, size)) == NULL) { -+ DMA_ERROR(("%s: dma_attach: out of tx memory, malloced %d bytes\n", -+ di->name, MALLOCED(osh))); -+ goto fail; -+ } -+ bzero((char *)di->txp, size); -+ } -+ -+ /* allocate rx packet pointer vector */ -+ if (nrxd) { -+ size = nrxd * sizeof(void *); -+ if ((di->rxp = MALLOC(osh, size)) == NULL) { -+ DMA_ERROR(("%s: dma_attach: out of rx memory, malloced %d bytes\n", -+ di->name, MALLOCED(osh))); -+ goto fail; -+ } -+ bzero((char *)di->rxp, size); -+ } -+ -+ /* allocate transmit descriptor ring, only need ntxd descriptors but it must be aligned */ -+ if (ntxd) { -+ if (!dma32_alloc(di, DMA_TX)) -+ goto fail; -+ } -+ -+ /* allocate receive descriptor ring, only need nrxd descriptors but it must be aligned */ -+ if (nrxd) { -+ if (!dma32_alloc(di, DMA_RX)) -+ goto fail; -+ } -+ -+ if ((di->ddoffsetlow == SB_PCI_DMA) && (di->txdpa > SB_PCI_DMA_SZ) && !di->addrext) { -+ DMA_ERROR(("%s: dma_attach: txdpa 0x%lx: addrext not supported\n", -+ di->name, di->txdpa)); -+ goto fail; -+ } -+ if ((di->ddoffsetlow == SB_PCI_DMA) && (di->rxdpa > SB_PCI_DMA_SZ) && !di->addrext) { -+ DMA_ERROR(("%s: dma_attach: rxdpa 0x%lx: addrext not supported\n", -+ di->name, di->rxdpa)); -+ goto fail; -+ } -+ -+ DMA_TRACE(("ddoffsetlow 0x%x ddoffsethigh 0x%x dataoffsetlow 0x%x dataoffsethigh " -+ "0x%x addrext %d\n", di->ddoffsetlow, di->ddoffsethigh, di->dataoffsetlow, -+ di->dataoffsethigh, di->addrext)); -+ -+ /* allocate tx packet pointer vector and DMA mapping vectors */ -+ if (ntxd) { -+ -+ size = ntxd * sizeof(osldma_t **); -+ if ((di->txp_dmah = (osldma_t **)MALLOC(osh, size)) == NULL) -+ goto fail; -+ bzero((char*)di->txp_dmah, size); -+ }else -+ di->txp_dmah = NULL; -+ -+ /* allocate rx packet pointer vector and DMA mapping vectors */ -+ if (nrxd) { -+ -+ size = nrxd * sizeof(osldma_t **); -+ if ((di->rxp_dmah = (osldma_t **)MALLOC(osh, size)) == NULL) -+ goto fail; -+ bzero((char*)di->rxp_dmah, size); -+ -+ } else -+ di->rxp_dmah = NULL; -+ -+ /* initialize opsvec of function pointers */ -+ di->hnddma.di_fn = dma32proc; -+ -+ return ((hnddma_t *)di); -+ -+fail: -+ _dma_detach(di); -+ return (NULL); -+} -+ -+/* init the tx or rx descriptor */ -+static INLINE void -+dma32_dd_upd(dma_info_t *di, dma32dd_t *ddring, ulong pa, uint outidx, uint32 *flags, -+ uint32 bufcount) -+{ -+ /* dma32 uses 32 bits control to fit both flags and bufcounter */ -+ *flags = *flags | (bufcount & CTRL_BC_MASK); -+ -+ if ((di->dataoffsetlow != SB_PCI_DMA) || !(pa & PCI32ADDR_HIGH)) { -+ W_SM(&ddring[outidx].addr, BUS_SWAP32(pa + di->dataoffsetlow)); -+ W_SM(&ddring[outidx].ctrl, BUS_SWAP32(*flags)); -+ } else { -+ /* address extension */ -+ uint32 ae; -+ ASSERT(di->addrext); -+ ae = (pa & PCI32ADDR_HIGH) >> PCI32ADDR_HIGH_SHIFT; -+ pa &= ~PCI32ADDR_HIGH; -+ -+ *flags |= (ae << CTRL_AE_SHIFT); -+ W_SM(&ddring[outidx].addr, BUS_SWAP32(pa + di->dataoffsetlow)); -+ W_SM(&ddring[outidx].ctrl, BUS_SWAP32(*flags)); -+ } -+} -+ -+static bool -+_dma32_addrext(osl_t *osh, dma32regs_t *dma32regs) -+{ -+ uint32 w; -+ -+ OR_REG(osh, &dma32regs->control, XC_AE); -+ w = R_REG(osh, &dma32regs->control); -+ AND_REG(osh, &dma32regs->control, ~XC_AE); -+ return ((w & XC_AE) == XC_AE); -+} -+ -+/* !! may be called with core in reset */ -+static void -+_dma_detach(dma_info_t *di) -+{ -+ if (di == NULL) -+ return; -+ -+ DMA_TRACE(("%s: dma_detach\n", di->name)); -+ -+ /* shouldn't be here if descriptors are unreclaimed */ -+ ASSERT(di->txin == di->txout); -+ ASSERT(di->rxin == di->rxout); -+ -+ /* free dma descriptor rings */ -+ if (di->txd32) -+ DMA_FREE_CONSISTENT(di->osh, ((int8*)di->txd32 - di->txdalign), -+ di->txdalloc, (di->txdpa - di->txdalign), &di->tx_dmah); -+ if (di->rxd32) -+ DMA_FREE_CONSISTENT(di->osh, ((int8*)di->rxd32 - di->rxdalign), -+ di->rxdalloc, (di->rxdpa - di->rxdalign), &di->rx_dmah); -+ -+ /* free packet pointer vectors */ -+ if (di->txp) -+ MFREE(di->osh, (void *)di->txp, (di->ntxd * sizeof(void *))); -+ if (di->rxp) -+ MFREE(di->osh, (void *)di->rxp, (di->nrxd * sizeof(void *))); -+ -+ /* free tx packet DMA handles */ -+ if (di->txp_dmah) -+ MFREE(di->osh, (void *)di->txp_dmah, di->ntxd * sizeof(osldma_t **)); -+ -+ /* free rx packet DMA handles */ -+ if (di->rxp_dmah) -+ MFREE(di->osh, (void *)di->rxp_dmah, di->nrxd * sizeof(osldma_t **)); -+ -+ /* free our private info structure */ -+ MFREE(di->osh, (void *)di, sizeof(dma_info_t)); -+ -+} -+ -+/* return TRUE if this dma engine supports DmaExtendedAddrChanges, otherwise FALSE */ -+static bool -+_dma_isaddrext(dma_info_t *di) -+{ -+ if (di->d32txregs) -+ return (_dma32_addrext(di->osh, di->d32txregs)); -+ else if (di->d32rxregs) -+ return (_dma32_addrext(di->osh, di->d32rxregs)); -+ return FALSE; -+} -+ -+/* initialize descriptor table base address */ -+static void -+_dma_ddtable_init(dma_info_t *di, uint direction, ulong pa) -+{ -+ if ((di->ddoffsetlow != SB_PCI_DMA) || !(pa & PCI32ADDR_HIGH)) { -+ if (direction == DMA_TX) -+ W_REG(di->osh, &di->d32txregs->addr, (pa + di->ddoffsetlow)); -+ else -+ W_REG(di->osh, &di->d32rxregs->addr, (pa + di->ddoffsetlow)); -+ } else { -+ /* dma32 address extension */ -+ uint32 ae; -+ ASSERT(di->addrext); -+ -+ /* shift the high bit(s) from pa to ae */ -+ ae = (pa & PCI32ADDR_HIGH) >> PCI32ADDR_HIGH_SHIFT; -+ pa &= ~PCI32ADDR_HIGH; -+ -+ if (direction == DMA_TX) { -+ W_REG(di->osh, &di->d32txregs->addr, (pa + di->ddoffsetlow)); -+ SET_REG(di->osh, &di->d32txregs->control, XC_AE, ae <osh, &di->d32rxregs->addr, (pa + di->ddoffsetlow)); -+ SET_REG(di->osh, &di->d32rxregs->control, RC_AE, ae <name)); -+ OR_REG(di->osh, &di->d32txregs->control, XC_LE); -+} -+ -+static void -+_dma_rxinit(dma_info_t *di) -+{ -+ DMA_TRACE(("%s: dma_rxinit\n", di->name)); -+ -+ if (di->nrxd == 0) -+ return; -+ -+ di->rxin = di->rxout = 0; -+ -+ /* clear rx descriptor ring */ -+ BZERO_SM((void *)di->rxd32, (di->nrxd * sizeof(dma32dd_t))); -+ _dma_rxenable(di); -+ _dma_ddtable_init(di, DMA_RX, di->rxdpa); -+} -+ -+static void -+_dma_rxenable(dma_info_t *di) -+{ -+ DMA_TRACE(("%s: dma_rxenable\n", di->name)); -+ -+ W_REG(di->osh, &di->d32rxregs->control, ((di->rxoffset << RC_RO_SHIFT) | RC_RE)); -+} -+ -+/* !! rx entry routine, returns a pointer to the next frame received, -+ * or NULL if there are no more -+ */ -+static void * -+_dma_rx(dma_info_t *di) -+{ -+ void *p; -+ uint len; -+ int skiplen = 0; -+ -+ while ((p = _dma_getnextrxp(di, FALSE))) { -+ /* skip giant packets which span multiple rx descriptors */ -+ if (skiplen > 0) { -+ skiplen -= di->rxbufsize; -+ if (skiplen < 0) -+ skiplen = 0; -+ PKTFREE(di->osh, p, FALSE); -+ continue; -+ } -+ -+ len = ltoh16(*(uint16*)(PKTDATA(di->osh, p))); -+ DMA_TRACE(("%s: dma_rx len %d\n", di->name, len)); -+ -+ /* bad frame length check */ -+ if (len > (di->rxbufsize - di->rxoffset)) { -+ DMA_ERROR(("%s: dma_rx: bad frame length (%d)\n", di->name, len)); -+ if (len > 0) -+ skiplen = len - (di->rxbufsize - di->rxoffset); -+ PKTFREE(di->osh, p, FALSE); -+ di->hnddma.rxgiants++; -+ continue; -+ } -+ -+ /* set actual length */ -+ PKTSETLEN(di->osh, p, (di->rxoffset + len)); -+ -+ break; -+ } -+ -+ return (p); -+} -+ -+/* post receive buffers */ -+static void -+_dma_rxfill(dma_info_t *di) -+{ -+ void *p; -+ uint rxin, rxout; -+ uint32 flags = 0; -+ uint n; -+ uint i; -+ uint32 pa; -+ uint extra_offset = 0; -+ -+ /* -+ * Determine how many receive buffers we're lacking -+ * from the full complement, allocate, initialize, -+ * and post them, then update the chip rx lastdscr. -+ */ -+ -+ rxin = di->rxin; -+ rxout = di->rxout; -+ -+ n = di->nrxpost - NRXDACTIVE(rxin, rxout); -+ -+ DMA_TRACE(("%s: dma_rxfill: post %d\n", di->name, n)); -+ -+ if (di->rxbufsize > BCMEXTRAHDROOM) -+ extra_offset = BCMEXTRAHDROOM; -+ -+ for (i = 0; i < n; i++) { -+ /* the di->rxbufsize doesn't include the extra headroom, we need to add it to the -+ size to be allocated -+ */ -+ if ((p = PKTGET(di->osh, di->rxbufsize + extra_offset, -+ FALSE)) == NULL) { -+ DMA_ERROR(("%s: dma_rxfill: out of rxbufs\n", di->name)); -+ di->hnddma.rxnobuf++; -+ break; -+ } -+ /* reserve an extra headroom, if applicable */ -+ if (extra_offset) -+ PKTPULL(di->osh, p, extra_offset); -+ -+ /* Do a cached write instead of uncached write since DMA_MAP -+ * will flush the cache. -+ */ -+ *(uint32*)(PKTDATA(di->osh, p)) = 0; -+ -+ pa = (uint32) DMA_MAP(di->osh, PKTDATA(di->osh, p), -+ di->rxbufsize, DMA_RX, p); -+ -+ ASSERT(ISALIGNED(pa, 4)); -+ -+ /* save the free packet pointer */ -+ ASSERT(di->rxp[rxout] == NULL); -+ di->rxp[rxout] = p; -+ -+ /* reset flags for each descriptor */ -+ flags = 0; -+ if (rxout == (di->nrxd - 1)) -+ flags = CTRL_EOT; -+ dma32_dd_upd(di, di->rxd32, pa, rxout, &flags, di->rxbufsize); -+ rxout = NEXTRXD(rxout); -+ } -+ -+ di->rxout = rxout; -+ -+ /* update the chip lastdscr pointer */ -+ W_REG(di->osh, &di->d32rxregs->ptr, I2B(rxout, dma32dd_t)); -+} -+ -+/* like getnexttxp but no reclaim */ -+static void * -+_dma_peeknexttxp(dma_info_t *di) -+{ -+ uint end, i; -+ -+ if (di->ntxd == 0) -+ return (NULL); -+ -+ end = B2I(R_REG(di->osh, &di->d32txregs->status) & XS_CD_MASK, dma32dd_t); -+ -+ for (i = di->txin; i != end; i = NEXTTXD(i)) -+ if (di->txp[i]) -+ return (di->txp[i]); -+ -+ return (NULL); -+} -+ -+static void -+_dma_rxreclaim(dma_info_t *di) -+{ -+ void *p; -+ -+ /* "unused local" warning suppression for OSLs that -+ * define PKTFREE() without using the di->osh arg -+ */ -+ di = di; -+ -+ DMA_TRACE(("%s: dma_rxreclaim\n", di->name)); -+ -+ while ((p = _dma_getnextrxp(di, TRUE))) -+ PKTFREE(di->osh, p, FALSE); -+} -+ -+static void * -+_dma_getnextrxp(dma_info_t *di, bool forceall) -+{ -+ if (di->nrxd == 0) -+ return (NULL); -+ -+ return dma32_getnextrxp(di, forceall); -+} -+ -+static void -+_dma_txblock(dma_info_t *di) -+{ -+ di->hnddma.txavail = 0; -+} -+ -+static void -+_dma_txunblock(dma_info_t *di) -+{ -+ di->hnddma.txavail = di->ntxd - NTXDACTIVE(di->txin, di->txout) - 1; -+} -+ -+static uint -+_dma_txactive(dma_info_t *di) -+{ -+ return (NTXDACTIVE(di->txin, di->txout)); -+} -+ -+static void -+_dma_counterreset(dma_info_t *di) -+{ -+ /* reset all software counter */ -+ di->hnddma.rxgiants = 0; -+ di->hnddma.rxnobuf = 0; -+ di->hnddma.txnobuf = 0; -+} -+ -+/* get the address of the var in order to change later */ -+static uintptr -+_dma_getvar(dma_info_t *di, char *name) -+{ -+ if (!strcmp(name, "&txavail")) -+ return ((uintptr) &(di->hnddma.txavail)); -+ else { -+ ASSERT(0); -+ } -+ return (0); -+} -+ -+void -+dma_txpioloopback(osl_t *osh, dma32regs_t *regs) -+{ -+ OR_REG(osh, ®s->control, XC_LE); -+} -+ -+ -+ -+/* 32 bits DMA functions */ -+static void -+dma32_txinit(dma_info_t *di) -+{ -+ DMA_TRACE(("%s: dma_txinit\n", di->name)); -+ -+ if (di->ntxd == 0) -+ return; -+ -+ di->txin = di->txout = 0; -+ di->hnddma.txavail = di->ntxd - 1; -+ -+ /* clear tx descriptor ring */ -+ BZERO_SM((void *)di->txd32, (di->ntxd * sizeof(dma32dd_t))); -+ W_REG(di->osh, &di->d32txregs->control, XC_XE); -+ _dma_ddtable_init(di, DMA_TX, di->txdpa); -+} -+ -+static bool -+dma32_txenabled(dma_info_t *di) -+{ -+ uint32 xc; -+ -+ /* If the chip is dead, it is not enabled :-) */ -+ xc = R_REG(di->osh, &di->d32txregs->control); -+ return ((xc != 0xffffffff) && (xc & XC_XE)); -+} -+ -+static void -+dma32_txsuspend(dma_info_t *di) -+{ -+ DMA_TRACE(("%s: dma_txsuspend\n", di->name)); -+ -+ if (di->ntxd == 0) -+ return; -+ -+ OR_REG(di->osh, &di->d32txregs->control, XC_SE); -+} -+ -+static void -+dma32_txresume(dma_info_t *di) -+{ -+ DMA_TRACE(("%s: dma_txresume\n", di->name)); -+ -+ if (di->ntxd == 0) -+ return; -+ -+ AND_REG(di->osh, &di->d32txregs->control, ~XC_SE); -+} -+ -+static bool -+dma32_txsuspended(dma_info_t *di) -+{ -+ return (di->ntxd == 0) || ((R_REG(di->osh, &di->d32txregs->control) & XC_SE) == XC_SE); -+} -+ -+static void -+dma32_txreclaim(dma_info_t *di, bool forceall) -+{ -+ void *p; -+ -+ DMA_TRACE(("%s: dma_txreclaim %s\n", di->name, forceall ? "all" : "")); -+ -+ while ((p = dma32_getnexttxp(di, forceall))) -+ PKTFREE(di->osh, p, TRUE); -+} -+ -+static bool -+dma32_txstopped(dma_info_t *di) -+{ -+ return ((R_REG(di->osh, &di->d32txregs->status) & XS_XS_MASK) == XS_XS_STOPPED); -+} -+ -+static bool -+dma32_rxstopped(dma_info_t *di) -+{ -+ return ((R_REG(di->osh, &di->d32rxregs->status) & RS_RS_MASK) == RS_RS_STOPPED); -+} -+ -+static bool -+dma32_alloc(dma_info_t *di, uint direction) -+{ -+ uint size; -+ uint ddlen; -+ void *va; -+ -+ ddlen = sizeof(dma32dd_t); -+ -+ size = (direction == DMA_TX) ? (di->ntxd * ddlen) : (di->nrxd * ddlen); -+ -+ if (!ISALIGNED(DMA_CONSISTENT_ALIGN, D32RINGALIGN)) -+ size += D32RINGALIGN; -+ -+ -+ if (direction == DMA_TX) { -+ if ((va = DMA_ALLOC_CONSISTENT(di->osh, size, &di->txdpa, &di->tx_dmah)) == NULL) { -+ DMA_ERROR(("%s: dma_attach: DMA_ALLOC_CONSISTENT(ntxd) failed\n", -+ di->name)); -+ return FALSE; -+ } -+ -+ di->txd32 = (dma32dd_t *) ROUNDUP((uintptr)va, D32RINGALIGN); -+ di->txdalign = (uint)((int8*)di->txd32 - (int8*)va); -+ di->txdpa += di->txdalign; -+ di->txdalloc = size; -+ ASSERT(ISALIGNED((uintptr)di->txd32, D32RINGALIGN)); -+ } else { -+ if ((va = DMA_ALLOC_CONSISTENT(di->osh, size, &di->rxdpa, &di->rx_dmah)) == NULL) { -+ DMA_ERROR(("%s: dma_attach: DMA_ALLOC_CONSISTENT(nrxd) failed\n", -+ di->name)); -+ return FALSE; -+ } -+ di->rxd32 = (dma32dd_t *) ROUNDUP((uintptr)va, D32RINGALIGN); -+ di->rxdalign = (uint)((int8*)di->rxd32 - (int8*)va); -+ di->rxdpa += di->rxdalign; -+ di->rxdalloc = size; -+ ASSERT(ISALIGNED((uintptr)di->rxd32, D32RINGALIGN)); -+ } -+ -+ return TRUE; -+} -+ -+static bool -+dma32_txreset(dma_info_t *di) -+{ -+ uint32 status; -+ -+ if (di->ntxd == 0) -+ return TRUE; -+ -+ /* suspend tx DMA first */ -+ W_REG(di->osh, &di->d32txregs->control, XC_SE); -+ SPINWAIT(((status = (R_REG(di->osh, &di->d32txregs->status) & XS_XS_MASK)) -+ != XS_XS_DISABLED) && -+ (status != XS_XS_IDLE) && -+ (status != XS_XS_STOPPED), -+ (10000)); -+ -+ W_REG(di->osh, &di->d32txregs->control, 0); -+ SPINWAIT(((status = (R_REG(di->osh, -+ &di->d32txregs->status) & XS_XS_MASK)) != XS_XS_DISABLED), -+ 10000); -+ -+ /* wait for the last transaction to complete */ -+ OSL_DELAY(300); -+ -+ return (status == XS_XS_DISABLED); -+} -+ -+static bool -+dma32_rxidle(dma_info_t *di) -+{ -+ DMA_TRACE(("%s: dma_rxidle\n", di->name)); -+ -+ if (di->nrxd == 0) -+ return TRUE; -+ -+ return ((R_REG(di->osh, &di->d32rxregs->status) & RS_CD_MASK) == -+ R_REG(di->osh, &di->d32rxregs->ptr)); -+} -+ -+static bool -+dma32_rxreset(dma_info_t *di) -+{ -+ uint32 status; -+ -+ if (di->nrxd == 0) -+ return TRUE; -+ -+ W_REG(di->osh, &di->d32rxregs->control, 0); -+ SPINWAIT(((status = (R_REG(di->osh, -+ &di->d32rxregs->status) & RS_RS_MASK)) != RS_RS_DISABLED), -+ 10000); -+ -+ return (status == RS_RS_DISABLED); -+} -+ -+static bool -+dma32_rxenabled(dma_info_t *di) -+{ -+ uint32 rc; -+ -+ rc = R_REG(di->osh, &di->d32rxregs->control); -+ return ((rc != 0xffffffff) && (rc & RC_RE)); -+} -+ -+static bool -+dma32_txsuspendedidle(dma_info_t *di) -+{ -+ if (di->ntxd == 0) -+ return TRUE; -+ -+ if (!(R_REG(di->osh, &di->d32txregs->control) & XC_SE)) -+ return 0; -+ -+ if ((R_REG(di->osh, &di->d32txregs->status) & XS_XS_MASK) != XS_XS_IDLE) -+ return 0; -+ -+ OSL_DELAY(2); -+ return ((R_REG(di->osh, &di->d32txregs->status) & XS_XS_MASK) == XS_XS_IDLE); -+} -+ -+/* !! tx entry routine -+ * supports full 32bit dma engine buffer addressing so -+ * dma buffers can cross 4 Kbyte page boundaries. -+ */ -+static int -+dma32_txfast(dma_info_t *di, void *p0, bool commit) -+{ -+ void *p, *next; -+ uchar *data; -+ uint len; -+ uint txout; -+ uint32 flags = 0; -+ uint32 pa; -+ -+ DMA_TRACE(("%s: dma_txfast\n", di->name)); -+ -+ txout = di->txout; -+ -+ /* -+ * Walk the chain of packet buffers -+ * allocating and initializing transmit descriptor entries. -+ */ -+ for (p = p0; p; p = next) { -+ data = PKTDATA(di->osh, p); -+ len = PKTLEN(di->osh, p); -+ next = PKTNEXT(di->osh, p); -+ -+ /* return nonzero if out of tx descriptors */ -+ if (NEXTTXD(txout) == di->txin) -+ goto outoftxd; -+ -+ if (len == 0) -+ continue; -+ -+ /* get physical address of buffer start */ -+ pa = (uint32) DMA_MAP(di->osh, data, len, DMA_TX, p); -+ -+ flags = 0; -+ if (p == p0) -+ flags |= CTRL_SOF; -+ if (next == NULL) -+ flags |= (CTRL_IOC | CTRL_EOF); -+ if (txout == (di->ntxd - 1)) -+ flags |= CTRL_EOT; -+ -+ dma32_dd_upd(di, di->txd32, pa, txout, &flags, len); -+ ASSERT(di->txp[txout] == NULL); -+ -+ txout = NEXTTXD(txout); -+ } -+ -+ /* if last txd eof not set, fix it */ -+ if (!(flags & CTRL_EOF)) -+ W_SM(&di->txd32[PREVTXD(txout)].ctrl, BUS_SWAP32(flags | CTRL_IOC | CTRL_EOF)); -+ -+ /* save the packet */ -+ di->txp[PREVTXD(txout)] = p0; -+ -+ /* bump the tx descriptor index */ -+ di->txout = txout; -+ -+ /* kick the chip */ -+ if (commit) -+ W_REG(di->osh, &di->d32txregs->ptr, I2B(txout, dma32dd_t)); -+ -+ /* tx flow control */ -+ di->hnddma.txavail = di->ntxd - NTXDACTIVE(di->txin, di->txout) - 1; -+ -+ return (0); -+ -+outoftxd: -+ DMA_ERROR(("%s: dma_txfast: out of txds\n", di->name)); -+ PKTFREE(di->osh, p0, TRUE); -+ di->hnddma.txavail = 0; -+ di->hnddma.txnobuf++; -+ return (-1); -+} -+ -+/* -+ * Reclaim next completed txd (txds if using chained buffers) and -+ * return associated packet. -+ * If 'force' is true, reclaim txd(s) and return associated packet -+ * regardless of the value of the hardware "curr" pointer. -+ */ -+static void * -+dma32_getnexttxp(dma_info_t *di, bool forceall) -+{ -+ uint start, end, i; -+ void *txp; -+ -+ DMA_TRACE(("%s: dma_getnexttxp %s\n", di->name, forceall ? "all" : "")); -+ -+ if (di->ntxd == 0) -+ return (NULL); -+ -+ txp = NULL; -+ -+ start = di->txin; -+ if (forceall) -+ end = di->txout; -+ else -+ end = B2I(R_REG(di->osh, &di->d32txregs->status) & XS_CD_MASK, dma32dd_t); -+ -+ if ((start == 0) && (end > di->txout)) -+ goto bogus; -+ -+ for (i = start; i != end && !txp; i = NEXTTXD(i)) { -+ DMA_UNMAP(di->osh, (BUS_SWAP32(R_SM(&di->txd32[i].addr)) - di->dataoffsetlow), -+ (BUS_SWAP32(R_SM(&di->txd32[i].ctrl)) & CTRL_BC_MASK), -+ DMA_TX, di->txp[i]); -+ -+ W_SM(&di->txd32[i].addr, 0xdeadbeef); -+ txp = di->txp[i]; -+ di->txp[i] = NULL; -+ } -+ -+ di->txin = i; -+ -+ /* tx flow control */ -+ di->hnddma.txavail = di->ntxd - NTXDACTIVE(di->txin, di->txout) - 1; -+ -+ return (txp); -+ -+bogus: -+/* -+ DMA_ERROR(("dma_getnexttxp: bogus curr: start %d end %d txout %d force %d\n", -+ start, end, di->txout, forceall)); -+*/ -+ return (NULL); -+} -+ -+static void * -+dma32_getnextrxp(dma_info_t *di, bool forceall) -+{ -+ uint i; -+ void *rxp; -+ -+ /* if forcing, dma engine must be disabled */ -+ ASSERT(!forceall || !dma32_rxenabled(di)); -+ -+ i = di->rxin; -+ -+ /* return if no packets posted */ -+ if (i == di->rxout) -+ return (NULL); -+ -+ /* ignore curr if forceall */ -+ if (!forceall && (i == B2I(R_REG(di->osh, &di->d32rxregs->status) & RS_CD_MASK, dma32dd_t))) -+ return (NULL); -+ -+ /* get the packet pointer that corresponds to the rx descriptor */ -+ rxp = di->rxp[i]; -+ ASSERT(rxp); -+ di->rxp[i] = NULL; -+ -+ /* clear this packet from the descriptor ring */ -+ DMA_UNMAP(di->osh, (BUS_SWAP32(R_SM(&di->rxd32[i].addr)) - di->dataoffsetlow), -+ di->rxbufsize, DMA_RX, rxp); -+ -+ W_SM(&di->rxd32[i].addr, 0xdeadbeef); -+ -+ di->rxin = NEXTRXD(i); -+ -+ return (rxp); -+} -+ -+/* -+ * Rotate all active tx dma ring entries "forward" by (ActiveDescriptor - txin). -+ */ -+static void -+dma32_txrotate(dma_info_t *di) -+{ -+ uint ad; -+ uint nactive; -+ uint rot; -+ uint old, new; -+ uint32 w; -+ uint first, last; -+ -+ ASSERT(dma32_txsuspendedidle(di)); -+ -+ nactive = _dma_txactive(di); -+ ad = B2I(((R_REG(di->osh, &di->d32txregs->status) & XS_AD_MASK) >> XS_AD_SHIFT), dma32dd_t); -+ rot = TXD(ad - di->txin); -+ -+ ASSERT(rot < di->ntxd); -+ -+ /* full-ring case is a lot harder - don't worry about this */ -+ if (rot >= (di->ntxd - nactive)) { -+ DMA_ERROR(("%s: dma_txrotate: ring full - punt\n", di->name)); -+ return; -+ } -+ -+ first = di->txin; -+ last = PREVTXD(di->txout); -+ -+ /* move entries starting at last and moving backwards to first */ -+ for (old = last; old != PREVTXD(first); old = PREVTXD(old)) { -+ new = TXD(old + rot); -+ -+ /* -+ * Move the tx dma descriptor. -+ * EOT is set only in the last entry in the ring. -+ */ -+ w = BUS_SWAP32(R_SM(&di->txd32[old].ctrl)) & ~CTRL_EOT; -+ if (new == (di->ntxd - 1)) -+ w |= CTRL_EOT; -+ W_SM(&di->txd32[new].ctrl, BUS_SWAP32(w)); -+ W_SM(&di->txd32[new].addr, R_SM(&di->txd32[old].addr)); -+ -+ /* zap the old tx dma descriptor address field */ -+ W_SM(&di->txd32[old].addr, BUS_SWAP32(0xdeadbeef)); -+ -+ /* move the corresponding txp[] entry */ -+ ASSERT(di->txp[new] == NULL); -+ di->txp[new] = di->txp[old]; -+ di->txp[old] = NULL; -+ } -+ -+ /* update txin and txout */ -+ di->txin = ad; -+ di->txout = TXD(di->txout + rot); -+ di->hnddma.txavail = di->ntxd - NTXDACTIVE(di->txin, di->txout) - 1; -+ -+ /* kick the chip */ -+ W_REG(di->osh, &di->d32txregs->ptr, I2B(di->txout, dma32dd_t)); -+} -+ -+ -+uint -+dma_addrwidth(sb_t *sbh, void *dmaregs) -+{ -+ dma32regs_t *dma32regs; -+ osl_t *osh; -+ -+ osh = sb_osh(sbh); -+ -+ /* Start checking for 32-bit / 30-bit addressing */ -+ dma32regs = (dma32regs_t *)dmaregs; -+ -+ /* For System Backplane, PCIE bus or addrext feature, 32-bits ok */ -+ if ((BUSTYPE(sbh->bustype) == SB_BUS) || -+ ((BUSTYPE(sbh->bustype) == PCI_BUS) && sbh->buscoretype == SB_PCIE) || -+ (_dma32_addrext(osh, dma32regs))) -+ return (DMADDRWIDTH_32); -+ -+ /* Fallthru */ -+ return (DMADDRWIDTH_30); -+} -diff -urN linux.old/drivers/net/wl/hnddma.h linux.dev/drivers/net/wl/hnddma.h ---- linux.old/drivers/net/wl/hnddma.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux.dev/drivers/net/wl/hnddma.h 2006-04-28 02:20:44.000000000 +0200 -@@ -0,0 +1,156 @@ -+/* -+ * Generic Broadcom Home Networking Division (HND) DMA engine SW interface -+ * This supports the following chips: BCM42xx, 44xx, 47xx . -+ * -+ * Copyright 2006, Broadcom Corporation -+ * All Rights Reserved. -+ * -+ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY -+ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM -+ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS -+ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. -+ * $Id: hnddma.h,v 1.1.1.13 2006/04/08 06:13:39 honor Exp $ -+ */ -+ -+#ifndef _hnddma_h_ -+#define _hnddma_h_ -+ -+typedef const struct hnddma_pub hnddma_t; -+ -+/* dma function type */ -+typedef void (*di_detach_t)(hnddma_t *dmah); -+typedef bool (*di_txreset_t)(hnddma_t *dmah); -+typedef bool (*di_rxreset_t)(hnddma_t *dmah); -+typedef bool (*di_rxidle_t)(hnddma_t *dmah); -+typedef void (*di_txinit_t)(hnddma_t *dmah); -+typedef bool (*di_txenabled_t)(hnddma_t *dmah); -+typedef void (*di_rxinit_t)(hnddma_t *dmah); -+typedef void (*di_txsuspend_t)(hnddma_t *dmah); -+typedef void (*di_txresume_t)(hnddma_t *dmah); -+typedef bool (*di_txsuspended_t)(hnddma_t *dmah); -+typedef bool (*di_txsuspendedidle_t)(hnddma_t *dmah); -+typedef int (*di_txfast_t)(hnddma_t *dmah, void *p, bool commit); -+typedef void (*di_fifoloopbackenable_t)(hnddma_t *dmah); -+typedef bool (*di_txstopped_t)(hnddma_t *dmah); -+typedef bool (*di_rxstopped_t)(hnddma_t *dmah); -+typedef bool (*di_rxenable_t)(hnddma_t *dmah); -+typedef bool (*di_rxenabled_t)(hnddma_t *dmah); -+typedef void* (*di_rx_t)(hnddma_t *dmah); -+typedef void (*di_rxfill_t)(hnddma_t *dmah); -+typedef void (*di_txreclaim_t)(hnddma_t *dmah, bool forceall); -+typedef void (*di_rxreclaim_t)(hnddma_t *dmah); -+typedef uintptr (*di_getvar_t)(hnddma_t *dmah, char *name); -+typedef void* (*di_getnexttxp_t)(hnddma_t *dmah, bool forceall); -+typedef void* (*di_getnextrxp_t)(hnddma_t *dmah, bool forceall); -+typedef void* (*di_peeknexttxp_t)(hnddma_t *dmah); -+typedef void (*di_txblock_t)(hnddma_t *dmah); -+typedef void (*di_txunblock_t)(hnddma_t *dmah); -+typedef uint (*di_txactive_t)(hnddma_t *dmah); -+typedef void (*di_txrotate_t)(hnddma_t *dmah); -+typedef void (*di_counterreset_t)(hnddma_t *dmah); -+typedef char* (*di_dump_t)(hnddma_t *dmah, struct bcmstrbuf *b, bool dumpring); -+typedef char* (*di_dumptx_t)(hnddma_t *dmah, struct bcmstrbuf *b, bool dumpring); -+typedef char* (*di_dumprx_t)(hnddma_t *dmah, struct bcmstrbuf *b, bool dumpring); -+ -+/* dma opsvec */ -+typedef struct di_fcn_s { -+ di_detach_t detach; -+ di_txinit_t txinit; -+ di_txreset_t txreset; -+ di_txenabled_t txenabled; -+ di_txsuspend_t txsuspend; -+ di_txresume_t txresume; -+ di_txsuspended_t txsuspended; -+ di_txsuspendedidle_t txsuspendedidle; -+ di_txfast_t txfast; -+ di_txstopped_t txstopped; -+ di_txreclaim_t txreclaim; -+ di_getnexttxp_t getnexttxp; -+ di_peeknexttxp_t peeknexttxp; -+ di_txblock_t txblock; -+ di_txunblock_t txunblock; -+ di_txactive_t txactive; -+ di_txrotate_t txrotate; -+ -+ di_rxinit_t rxinit; -+ di_rxreset_t rxreset; -+ di_rxidle_t rxidle; -+ di_rxstopped_t rxstopped; -+ di_rxenable_t rxenable; -+ di_rxenabled_t rxenabled; -+ di_rx_t rx; -+ di_rxfill_t rxfill; -+ di_rxreclaim_t rxreclaim; -+ di_getnextrxp_t getnextrxp; -+ -+ di_fifoloopbackenable_t fifoloopbackenable; -+ di_getvar_t d_getvar; -+ di_counterreset_t counterreset; -+ di_dump_t dump; -+ di_dumptx_t dumptx; -+ di_dumprx_t dumprx; -+ uint endnum; -+} di_fcn_t; -+ -+/* -+ * Exported data structure (read-only) -+ */ -+/* export structure */ -+struct hnddma_pub { -+ di_fcn_t di_fn; /* DMA function pointers */ -+ uint txavail; /* # free tx descriptors */ -+ -+ /* rx error counters */ -+ uint rxgiants; /* rx giant frames */ -+ uint rxnobuf; /* rx out of dma descriptors */ -+ /* tx error counters */ -+ uint txnobuf; /* tx out of dma descriptors */ -+}; -+ -+ -+extern hnddma_t * dma_attach(osl_t *osh, char *name, sb_t *sbh, void *dmaregstx, void *dmaregsrx, -+ uint ntxd, uint nrxd, uint rxbufsize, uint nrxpost, uint rxoffset, -+ uint *msg_level); -+#define dma_detach(di) ((di)->di_fn.detach(di)) -+#define dma_txreset(di) ((di)->di_fn.txreset(di)) -+#define dma_rxreset(di) ((di)->di_fn.rxreset(di)) -+#define dma_rxidle(di) ((di)->di_fn.rxidle(di)) -+#define dma_txinit(di) ((di)->di_fn.txinit(di)) -+#define dma_txenabled(di) ((di)->di_fn.txenabled(di)) -+#define dma_rxinit(di) ((di)->di_fn.rxinit(di)) -+#define dma_txsuspend(di) ((di)->di_fn.txsuspend(di)) -+#define dma_txresume(di) ((di)->di_fn.txresume(di)) -+#define dma_txsuspended(di) ((di)->di_fn.txsuspended(di)) -+#define dma_txsuspendedidle(di) ((di)->di_fn.txsuspendedidle(di)) -+#define dma_txfast(di, p, commit) ((di)->di_fn.txfast(di, p, commit)) -+#define dma_fifoloopbackenable(di) ((di)->di_fn.fifoloopbackenable(di)) -+#define dma_txstopped(di) ((di)->di_fn.txstopped(di)) -+#define dma_rxstopped(di) ((di)->di_fn.rxstopped(di)) -+#define dma_rxenable(di) ((di)->di_fn.rxenable(di)) -+#define dma_rxenabled(di) ((di)->di_fn.rxenabled(di)) -+#define dma_rx(di) ((di)->di_fn.rx(di)) -+#define dma_rxfill(di) ((di)->di_fn.rxfill(di)) -+#define dma_txreclaim(di, forceall) ((di)->di_fn.txreclaim(di, forceall)) -+#define dma_rxreclaim(di) ((di)->di_fn.rxreclaim(di)) -+#define dma_getvar(di, name) ((di)->di_fn.d_getvar(di, name)) -+#define dma_getnexttxp(di, forceall) ((di)->di_fn.getnexttxp(di, forceall)) -+#define dma_getnextrxp(di, forceall) ((di)->di_fn.getnextrxp(di, forceall)) -+#define dma_peeknexttxp(di) ((di)->di_fn.peeknexttxp(di)) -+#define dma_txblock(di) ((di)->di_fn.txblock(di)) -+#define dma_txunblock(di) ((di)->di_fn.txunblock(di)) -+#define dma_txactive(di) ((di)->di_fn.txactive(di)) -+#define dma_txrotate(di) ((di)->di_fn.txrotate(di)) -+#define dma_counterreset(di) ((di)->di_fn.counterreset(di)) -+ -+#define DMA_DUMP_SIZE 2048 -+/* return addresswidth allowed -+ * This needs to be done after SB attach but before dma attach. -+ * SB attach provides ability to probe backplane and dma core capabilities -+ * This info is needed by DMA_ALLOC_CONSISTENT in dma attach -+ */ -+extern uint dma_addrwidth(sb_t *sbh, void *dmaregs); -+ -+/* pio helpers */ -+void dma_txpioloopback(osl_t *osh, dma32regs_t *); -+ -+#endif /* _hnddma_h_ */ -diff -urN linux.old/drivers/net/wl/linux_osl.c linux.dev/drivers/net/wl/linux_osl.c ---- linux.old/drivers/net/wl/linux_osl.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux.dev/drivers/net/wl/linux_osl.c 2006-04-28 02:29:46.000000000 +0200 -@@ -0,0 +1,269 @@ -+/* -+ * Linux OS Independent Layer -+ * -+ * Copyright 2006, Broadcom Corporation -+ * All Rights Reserved. -+ * -+ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY -+ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM -+ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS -+ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. -+ * -+ * $Id: linux_osl.c,v 1.1.1.14 2006/04/08 06:13:39 honor Exp $ -+ */ -+ -+#define LINUX_OSL -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include "linux_osl.h" -+#include -+#include -+#ifdef mips -+#include -+#endif /* mips */ -+#include -+ -+#define PCI_CFG_RETRY 10 -+ -+#define OS_HANDLE_MAGIC 0x1234abcd /* Magic # to recognise osh */ -+#define BCM_MEM_FILENAME_LEN 24 /* Mem. filename length */ -+ -+typedef struct bcm_mem_link { -+ struct bcm_mem_link *prev; -+ struct bcm_mem_link *next; -+ uint size; -+ int line; -+ char file[BCM_MEM_FILENAME_LEN]; -+} bcm_mem_link_t; -+ -+static int16 linuxbcmerrormap[] = \ -+{ 0, /* 0 */ -+ -EINVAL, /* BCME_ERROR */ -+ -EINVAL, /* BCME_BADARG */ -+ -EINVAL, /* BCME_BADOPTION */ -+ -EINVAL, /* BCME_NOTUP */ -+ -EINVAL, /* BCME_NOTDOWN */ -+ -EINVAL, /* BCME_NOTAP */ -+ -EINVAL, /* BCME_NOTSTA */ -+ -EINVAL, /* BCME_BADKEYIDX */ -+ -EINVAL, /* BCME_RADIOOFF */ -+ -EINVAL, /* BCME_NOTBANDLOCKED */ -+ -EINVAL, /* BCME_NOCLK */ -+ -EINVAL, /* BCME_BADRATESET */ -+ -EINVAL, /* BCME_BADBAND */ -+ -E2BIG, /* BCME_BUFTOOSHORT */ -+ -E2BIG, /* BCME_BUFTOOLONG */ -+ -EBUSY, /* BCME_BUSY */ -+ -EINVAL, /* BCME_NOTASSOCIATED */ -+ -EINVAL, /* BCME_BADSSIDLEN */ -+ -EINVAL, /* BCME_OUTOFRANGECHAN */ -+ -EINVAL, /* BCME_BADCHAN */ -+ -EFAULT, /* BCME_BADADDR */ -+ -ENOMEM, /* BCME_NORESOURCE */ -+ -EOPNOTSUPP, /* BCME_UNSUPPORTED */ -+ -EMSGSIZE, /* BCME_BADLENGTH */ -+ -EINVAL, /* BCME_NOTREADY */ -+ -EPERM, /* BCME_NOTPERMITTED */ -+ -ENOMEM, /* BCME_NOMEM */ -+ -EINVAL, /* BCME_ASSOCIATED */ -+ -ERANGE, /* BCME_RANGE */ -+ -EINVAL, /* BCME_NOTFOUND */ -+ -EINVAL, /* BCME_WME_NOT_ENABLED */ -+ -EINVAL, /* BCME_TSPEC_NOTFOUND */ -+ -EINVAL, /* BCME_ACM_NOTSUPPORTED */ -+ -EINVAL, /* BCME_NOT_WME_ASSOCIATION */ -+ -EIO, /* BCME_SDIO_ERROR */ -+ -ENODEV /* BCME_DONGLE_DOWN */ -+}; -+ -+/* translate bcmerrors into linux errors */ -+int -+osl_error(int bcmerror) -+{ -+ int abs_bcmerror; -+ int array_size = ARRAYSIZE(linuxbcmerrormap); -+ -+ abs_bcmerror = ABS(bcmerror); -+ -+ if (bcmerror > 0) -+ abs_bcmerror = 0; -+ -+ else if (abs_bcmerror >= array_size) -+ abs_bcmerror = BCME_ERROR; -+ -+ return linuxbcmerrormap[abs_bcmerror]; -+} -+ -+osl_t * -+osl_attach(void *pdev, bool pkttag) -+{ -+ osl_t *osh; -+ -+ osh = kmalloc(sizeof(osl_t), GFP_ATOMIC); -+ ASSERT(osh); -+ -+ bzero(osh, sizeof(osl_t)); -+ -+ /* -+ * check the cases where -+ * 1.Error code Added to bcmerror table, but forgot to add it to the OS -+ * dependent error code -+ * 2. Error code is added to the bcmerror table, but forgot to add the -+ * corresponding errorstring(dummy call to bcmerrorstr) -+ */ -+ bcmerrorstr(0); -+ ASSERT(ABS(BCME_LAST) == (ARRAYSIZE(linuxbcmerrormap) - 1)); -+ -+ osh->magic = OS_HANDLE_MAGIC; -+ osh->malloced = 0; -+ osh->failed = 0; -+ osh->dbgmem_list = NULL; -+ osh->pdev = pdev; -+ osh->pub.pkttag = pkttag; -+ -+ return osh; -+} -+ -+void -+osl_detach(osl_t *osh) -+{ -+ if (osh == NULL) -+ return; -+ -+ ASSERT(osh->magic == OS_HANDLE_MAGIC); -+ kfree(osh); -+} -+ -+/* Return a new packet. zero out pkttag */ -+void* -+osl_pktget(osl_t *osh, uint len, bool send) -+{ -+ struct sk_buff *skb; -+ -+ if ((skb = dev_alloc_skb(len))) { -+ skb_put(skb, len); -+ skb->priority = 0; -+ -+#ifdef BCMDBG_PKT -+ pktlist_add(&(osh->pktlist), (void *) skb); -+#endif /* BCMDBG_PKT */ -+ -+ osh->pub.pktalloced++; -+ } -+ -+ return ((void*) skb); -+} -+ -+/* Free the driver packet. Free the tag if present */ -+void -+osl_pktfree(osl_t *osh, void *p) -+{ -+ struct sk_buff *skb, *nskb; -+ -+ skb = (struct sk_buff*) p; -+ -+ /* perversion: we use skb->next to chain multi-skb packets */ -+ while (skb) { -+ nskb = skb->next; -+ skb->next = NULL; -+ -+#ifdef BCMDBG_PKT -+ pktlist_remove(&(osh->pktlist), (void *) skb); -+#endif /* BCMDBG_PKT */ -+ -+ if (skb->destructor) { -+ /* cannot kfree_skb() on hard IRQ (net/core/skbuff.c) if destructor exists -+ */ -+ dev_kfree_skb_any(skb); -+ } else { -+ /* can free immediately (even in_irq()) if destructor does not exist */ -+ dev_kfree_skb(skb); -+ } -+ -+ osh->pub.pktalloced--; -+ -+ skb = nskb; -+ } -+} -+ -+void* -+osl_malloc(osl_t *osh, uint size) -+{ -+ void *addr; -+ -+ /* only ASSERT if osh is defined */ -+ if (osh) -+ ASSERT(osh->magic == OS_HANDLE_MAGIC); -+ -+ if ((addr = kmalloc(size, GFP_ATOMIC)) == NULL) { -+ if (osh) -+ osh->failed++; -+ return (NULL); -+ } -+ if (osh) -+ osh->malloced += size; -+ -+ return (addr); -+} -+ -+void -+osl_mfree(osl_t *osh, void *addr, uint size) -+{ -+ if (osh) { -+ ASSERT(osh->magic == OS_HANDLE_MAGIC); -+ osh->malloced -= size; -+ } -+ kfree(addr); -+} -+ -+uint -+osl_malloced(osl_t *osh) -+{ -+ ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); -+ return (osh->malloced); -+} -+ -+uint osl_malloc_failed(osl_t *osh) -+{ -+ ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); -+ return (osh->failed); -+} -+ -+#undef osl_delay -+void -+osl_delay(uint usec) -+{ -+ OSL_DELAY(usec); -+} -+ -+/* Clone a packet. -+ * The pkttag contents are NOT cloned. -+ */ -+void * -+osl_pktdup(osl_t *osh, void *skb) -+{ -+ void * p; -+ -+ if ((p = skb_clone((struct sk_buff*)skb, GFP_ATOMIC)) == NULL) -+ return NULL; -+ -+ /* skb_clone copies skb->cb.. we don't want that */ -+ if (osh->pub.pkttag) -+ bzero((void*)((struct sk_buff *)p)->cb, OSL_PKTTAG_SZ); -+ -+ /* Increment the packet counter */ -+ osh->pub.pktalloced++; -+ return (p); -+} -+ -+uint -+osl_pktalloced(osl_t *osh) -+{ -+ return (osh->pub.pktalloced); -+} -+ -diff -urN linux.old/drivers/net/wl/linux_osl.h linux.dev/drivers/net/wl/linux_osl.h ---- linux.old/drivers/net/wl/linux_osl.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux.dev/drivers/net/wl/linux_osl.h 2006-05-02 17:44:29.000000000 +0200 -@@ -0,0 +1,171 @@ -+/* -+ * Linux OS Independent Layer -+ * -+ * Copyright 2006, Broadcom Corporation -+ * All Rights Reserved. -+ * -+ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY -+ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM -+ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS -+ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. -+ * -+ * $Id: linux_osl.h,v 1.1.1.13 2006/04/08 06:13:39 honor Exp $ -+ */ -+ -+#ifndef _linux_osl_h_ -+#define _linux_osl_h_ -+ -+#include -+#include -+#include -+ -+#define OSL_PKTTAG_SZ 32 /* Size of PktTag */ -+ -+/* osl handle type forward declaration */ -+typedef struct osl_dmainfo osldma_t; -+ -+/* OSL initialization */ -+extern osl_t *osl_attach(void *pdev, bool pkttag); -+extern void osl_detach(osl_t *osh); -+ -+/* host/bus architecture-specific byte swap */ -+#define BUS_SWAP32(v) (v) -+#define MALLOC_FAILED(osh) osl_malloc_failed((osh)) -+ -+extern void *osl_malloc(osl_t *osh, uint size); -+extern void osl_mfree(osl_t *osh, void *addr, uint size); -+extern uint osl_malloced(osl_t *osh); -+extern uint osl_malloc_failed(osl_t *osh); -+ -+/* API for DMA addressing capability */ -+#define DMA_MAP(osh, va, size, direction, p) \ -+ osl_dma_map((osh), (va), (size), (direction)) -+#define DMA_UNMAP(osh, pa, size, direction, p) \ -+ osl_dma_unmap((osh), (pa), (size), (direction)) -+static inline uint -+osl_dma_map(void *osh, void *va, uint size, int direction) -+{ -+ int dir; -+ struct pci_dev *dev; -+ -+ dev = (osh == NULL ? NULL : ((osl_t *)osh)->pdev); -+ dir = (direction == DMA_TX)? PCI_DMA_TODEVICE: PCI_DMA_FROMDEVICE; -+ return (pci_map_single(dev, va, size, dir)); -+} -+ -+static inline void -+osl_dma_unmap(void *osh, uint pa, uint size, int direction) -+{ -+ int dir; -+ struct pci_dev *dev; -+ -+ dev = (osh == NULL ? NULL : ((osl_t *)osh)->pdev); -+ dir = (direction == DMA_TX)? PCI_DMA_TODEVICE: PCI_DMA_FROMDEVICE; -+ pci_unmap_single(dev, (uint32)pa, size, dir); -+} -+ -+#define OSL_DMADDRWIDTH(osh, addrwidth) do {} while (0) -+#define DMA_CONSISTENT_ALIGN PAGE_SIZE -+#define DMA_ALLOC_CONSISTENT(osh, size, pap, dmah) \ -+ osl_dma_alloc_consistent((osh), (size), (pap)) -+#define DMA_FREE_CONSISTENT(osh, va, size, pa, dmah) \ -+ osl_dma_free_consistent((osh), (void*)(va), (size), (pa)) -+static inline void* -+osl_dma_alloc_consistent(osl_t *osh, uint size, ulong *pap) -+{ -+ return (pci_alloc_consistent(osh->pdev, size, (dma_addr_t*)pap)); -+} -+ -+static inline void -+osl_dma_free_consistent(osl_t *osh, void *va, uint size, ulong pa) -+{ -+ pci_free_consistent(osh->pdev, size, va, (dma_addr_t)pa); -+} -+ -+ -+/* register access macros */ -+#if defined(BCMJTAG) -+#include -+#define R_REG(osh, r) bcmjtag_read(NULL, (uint32)(r), sizeof(*(r))) -+#define W_REG(osh, r, v) bcmjtag_write(NULL, (uint32)(r), (uint32)(v), sizeof(*(r))) -+#endif /* defined(BCMSDIO) */ -+ -+/* packet primitives */ -+#define PKTGET(osh, len, send) osl_pktget((osh), (len), (send)) -+#define PKTFREE(osh, skb, send) osl_pktfree((osh), (skb)) -+#define PKTDATA(osh, skb) (((struct sk_buff*)(skb))->data) -+#define PKTLEN(osh, skb) (((struct sk_buff*)(skb))->len) -+#define PKTHEADROOM(osh, skb) (PKTDATA(osh, skb)-(((struct sk_buff*)(skb))->head)) -+#define PKTTAILROOM(osh, skb) ((((struct sk_buff*)(skb))->end)-(((struct sk_buff*)(skb))->tail)) -+#define PKTNEXT(osh, skb) (((struct sk_buff*)(skb))->next) -+#define PKTSETNEXT(osh, skb, x) (((struct sk_buff*)(skb))->next = (struct sk_buff*)(x)) -+#define PKTSETLEN(osh, skb, len) __skb_trim((struct sk_buff*)(skb), (len)) -+#define PKTPUSH(osh, skb, bytes) skb_push((struct sk_buff*)(skb), (bytes)) -+#define PKTPULL(osh, skb, bytes) skb_pull((struct sk_buff*)(skb), (bytes)) -+#define PKTDUP(osh, skb) osl_pktdup((osh), (skb)) -+#define PKTTAG(skb) ((void*)(((struct sk_buff*)(skb))->cb)) -+#define PKTALLOCED(osh) osl_pktalloced((osh)) -+#define PKTLIST_DUMP(osh, buf) -+ -+/* Convert a native(OS) packet to driver packet. -+ * In the process, native packet is destroyed, there is no copying -+ * Also, a packettag is zeroed out -+ */ -+static INLINE void * -+osl_pkt_frmnative(struct osl_pubinfo *osh, struct sk_buff *skb) -+{ -+ struct sk_buff *nskb; -+ -+ if (osh->pkttag) -+ bzero((void*)skb->cb, OSL_PKTTAG_SZ); -+ -+ /* Increment the packet counter */ -+ for (nskb = skb; nskb; nskb = nskb->next) { -+ osh->pktalloced++; -+ } -+ -+ return (void *)skb; -+} -+#define PKTFRMNATIVE(osh, skb) osl_pkt_frmnative(((struct osl_pubinfo *)osh), \ -+ (struct sk_buff*)(skb)) -+ -+/* Convert a driver packet to native(OS) packet -+ * In the process, packettag is zeroed out before sending up -+ * IP code depends on skb->cb to be setup correctly with various options -+ * In our case, that means it should be 0 -+ */ -+static INLINE struct sk_buff * -+osl_pkt_tonative(struct osl_pubinfo *osh, void *pkt) -+{ -+ struct sk_buff *nskb; -+ -+ if (osh->pkttag) -+ bzero(((struct sk_buff*)pkt)->cb, OSL_PKTTAG_SZ); -+ -+ /* Decrement the packet counter */ -+ for (nskb = (struct sk_buff *)pkt; nskb; nskb = nskb->next) { -+ osh->pktalloced--; -+ } -+ -+ return (struct sk_buff *)pkt; -+} -+#define PKTTONATIVE(osh, pkt) osl_pkt_tonative((struct osl_pubinfo *)(osh), (pkt)) -+ -+#define PKTLINK(skb) (((struct sk_buff*)(skb))->prev) -+#define PKTSETLINK(skb, x) (((struct sk_buff*)(skb))->prev = (struct sk_buff*)(x)) -+#define PKTPRIO(skb) (((struct sk_buff*)(skb))->priority) -+#define PKTSETPRIO(skb, x) (((struct sk_buff*)(skb))->priority = (x)) -+#define PKTSHARED(skb) (((struct sk_buff*)(skb))->cloned) -+ -+extern void *osl_pktget(osl_t *osh, uint len, bool send); -+extern void osl_pktfree(osl_t *osh, void *skb); -+extern void *osl_pktdup(osl_t *osh, void *skb); -+extern uint osl_pktalloced(osl_t *osh); -+ -+#define OSL_ERROR(bcmerror) osl_error(bcmerror) -+extern int osl_error(int bcmerror); -+ -+/* the largest reasonable packet buffer driver uses for ethernet MTU in bytes */ -+#define PKTBUFSZ 2048 /* largest reasonable packet buffer, driver uses for ethernet MTU */ -+ -+#endif /* _linux_osl_h_ */ -diff -urN linux.old/drivers/net/wl/pktq.h linux.dev/drivers/net/wl/pktq.h ---- linux.old/drivers/net/wl/pktq.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux.dev/drivers/net/wl/pktq.h 2006-04-28 02:11:49.000000000 +0200 -@@ -0,0 +1,97 @@ -+/* -+ * Misc useful os-independent macros and functions. -+ * -+ * Copyright 2006, Broadcom Corporation -+ * All Rights Reserved. -+ * -+ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY -+ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM -+ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS -+ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. -+ * $Id: bcmutils.h,v 1.1.1.16 2006/04/08 06:13:39 honor Exp $ -+ */ -+ -+#ifndef _pktq_h_ -+#define _pktq_h_ -+#include -+ -+/* osl multi-precedence packet queue */ -+ -+#define PKTQ_LEN_DEFAULT 128 /* Max 128 packets */ -+#define PKTQ_MAX_PREC 16 /* Maximum precedence levels */ -+ -+struct pktq { -+ struct pktq_prec { -+ void *head; /* first packet to dequeue */ -+ void *tail; /* last packet to dequeue */ -+ uint16 len; /* number of queued packets */ -+ uint16 max; /* maximum number of queued packets */ -+ } q[PKTQ_MAX_PREC]; -+ uint16 num_prec; /* number of precedences in use */ -+ uint16 hi_prec; /* rapid dequeue hint (>= highest non-empty prec) */ -+ uint16 max; /* total max packets */ -+ uint16 len; /* total number of packets */ -+}; -+ -+#define PKTQ_PREC_ITER(pq, prec) for (prec = (pq)->num_prec - 1; prec >= 0; prec--) -+ -+/* forward definition of ether_addr structure used by some function prototypes */ -+ -+struct ether_addr; -+ -+/* operations on a specific precedence in packet queue */ -+ -+#define pktq_psetmax(pq, prec, _max) ((pq)->q[prec].max = (_max)) -+#define pktq_plen(pq, prec) ((pq)->q[prec].len) -+#define pktq_pavail(pq, prec) ((pq)->q[prec].max - (pq)->q[prec].len) -+#define pktq_pfull(pq, prec) ((pq)->q[prec].len >= (pq)->q[prec].max) -+#define pktq_pempty(pq, prec) ((pq)->q[prec].len == 0) -+ -+#define pktq_ppeek(pq, prec) ((pq)->q[prec].head) -+#define pktq_ppeek_tail(pq, prec) ((pq)->q[prec].tail) -+ -+extern void *pktq_penq(struct pktq *pq, int prec, void *p); -+extern void *pktq_penq_head(struct pktq *pq, int prec, void *p); -+extern void *pktq_pdeq(struct pktq *pq, int prec); -+extern void *pktq_pdeq_tail(struct pktq *pq, int prec); -+/* Empty the queue at particular precedence level */ -+extern void pktq_pflush(osl_t *osh, struct pktq *pq, int prec, bool dir); -+/* Remove a specified packet from its queue */ -+extern bool pktq_pdel(struct pktq *pq, void *p, int prec); -+ -+/* operations on a set of precedences in packet queue */ -+ -+extern int pktq_mlen(struct pktq *pq, uint prec_bmp); -+extern void *pktq_mdeq(struct pktq *pq, uint prec_bmp, int *prec_out); -+ -+/* operations on packet queue as a whole */ -+ -+#define pktq_len(pq) ((int)(pq)->len) -+#define pktq_max(pq) ((int)(pq)->max) -+#define pktq_avail(pq) ((int)((pq)->max - (pq)->len)) -+#define pktq_full(pq) ((pq)->len >= (pq)->max) -+#define pktq_empty(pq) ((pq)->len == 0) -+ -+/* operations for single precedence queues */ -+#define pktenq(pq, p) pktq_penq((pq), 0, (p)) -+#define pktenq_head(pq, p) pktq_penq_head((pq), 0, (p)) -+#define pktdeq(pq) pktq_pdeq((pq), 0) -+#define pktdeq_tail(pq) pktq_pdeq_tail((pq), 0) -+ -+extern void pktq_init(struct pktq *pq, int num_prec, int max_len); -+/* prec_out may be NULL if caller is not interested in return value */ -+extern void *pktq_deq(struct pktq *pq, int *prec_out); -+extern void *pktq_deq_tail(struct pktq *pq, int *prec_out); -+extern void *pktq_peek(struct pktq *pq, int *prec_out); -+extern void *pktq_peek_tail(struct pktq *pq, int *prec_out); -+extern void pktq_flush(osl_t *osh, struct pktq *pq, bool dir); /* Empty the entire queue */ -+ -+/* externs */ -+/* packet */ -+extern uint pktcopy(osl_t *osh, void *p, uint offset, int len, uchar *buf); -+extern uint pkttotlen(osl_t *osh, void *p); -+extern void *pktlast(osl_t *osh, void *p); -+ -+extern void pktsetprio(void *pkt, bool update_vtag); -+ -+#endif /* _pktq_h_ */ -diff -urN linux.old/drivers/net/wl/sbhnddma.h linux.dev/drivers/net/wl/sbhnddma.h ---- linux.old/drivers/net/wl/sbhnddma.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux.dev/drivers/net/wl/sbhnddma.h 2006-04-28 02:20:47.000000000 +0200 -@@ -0,0 +1,284 @@ -+/* -+ * Generic Broadcom Home Networking Division (HND) DMA engine HW interface -+ * This supports the following chips: BCM42xx, 44xx, 47xx . -+ * -+ * Copyright 2006, Broadcom Corporation -+ * All Rights Reserved. -+ * -+ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY -+ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM -+ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS -+ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. -+ * -+ * $Id: sbhnddma.h,v 1.1.1.2 2006/02/27 03:43:16 honor Exp $ -+ */ -+ -+#ifndef _sbhnddma_h_ -+#define _sbhnddma_h_ -+ -+/* DMA structure: -+ * support two DMA engines: 32 bits address or 64 bit addressing -+ * basic DMA register set is per channel(transmit or receive) -+ * a pair of channels is defined for convenience -+ */ -+ -+ -+/* 32 bits addressing */ -+ -+/* dma registers per channel(xmt or rcv) */ -+typedef volatile struct { -+ uint32 control; /* enable, et al */ -+ uint32 addr; /* descriptor ring base address (4K aligned) */ -+ uint32 ptr; /* last descriptor posted to chip */ -+ uint32 status; /* current active descriptor, et al */ -+} dma32regs_t; -+ -+typedef volatile struct { -+ dma32regs_t xmt; /* dma tx channel */ -+ dma32regs_t rcv; /* dma rx channel */ -+} dma32regp_t; -+ -+typedef volatile struct { /* diag access */ -+ uint32 fifoaddr; /* diag address */ -+ uint32 fifodatalow; /* low 32bits of data */ -+ uint32 fifodatahigh; /* high 32bits of data */ -+ uint32 pad; /* reserved */ -+} dma32diag_t; -+ -+/* -+ * DMA Descriptor -+ * Descriptors are only read by the hardware, never written back. -+ */ -+typedef volatile struct { -+ uint32 ctrl; /* misc control bits & bufcount */ -+ uint32 addr; /* data buffer address */ -+} dma32dd_t; -+ -+/* -+ * Each descriptor ring must be 4096byte aligned, and fit within a single 4096byte page. -+ */ -+#define D32MAXRINGSZ 4096 -+#define D32RINGALIGN 4096 -+#define D32MAXDD (D32MAXRINGSZ / sizeof (dma32dd_t)) -+ -+/* transmit channel control */ -+#define XC_XE ((uint32)1 << 0) /* transmit enable */ -+#define XC_SE ((uint32)1 << 1) /* transmit suspend request */ -+#define XC_LE ((uint32)1 << 2) /* loopback enable */ -+#define XC_FL ((uint32)1 << 4) /* flush request */ -+#define XC_AE ((uint32)3 << 16) /* address extension bits */ -+#define XC_AE_SHIFT 16 -+ -+/* transmit descriptor table pointer */ -+#define XP_LD_MASK 0xfff /* last valid descriptor */ -+ -+/* transmit channel status */ -+#define XS_CD_MASK 0x0fff /* current descriptor pointer */ -+#define XS_XS_MASK 0xf000 /* transmit state */ -+#define XS_XS_SHIFT 12 -+#define XS_XS_DISABLED 0x0000 /* disabled */ -+#define XS_XS_ACTIVE 0x1000 /* active */ -+#define XS_XS_IDLE 0x2000 /* idle wait */ -+#define XS_XS_STOPPED 0x3000 /* stopped */ -+#define XS_XS_SUSP 0x4000 /* suspend pending */ -+#define XS_XE_MASK 0xf0000 /* transmit errors */ -+#define XS_XE_SHIFT 16 -+#define XS_XE_NOERR 0x00000 /* no error */ -+#define XS_XE_DPE 0x10000 /* descriptor protocol error */ -+#define XS_XE_DFU 0x20000 /* data fifo underrun */ -+#define XS_XE_BEBR 0x30000 /* bus error on buffer read */ -+#define XS_XE_BEDA 0x40000 /* bus error on descriptor access */ -+#define XS_AD_MASK 0xfff00000 /* active descriptor */ -+#define XS_AD_SHIFT 20 -+ -+/* receive channel control */ -+#define RC_RE ((uint32)1 << 0) /* receive enable */ -+#define RC_RO_MASK 0xfe /* receive frame offset */ -+#define RC_RO_SHIFT 1 -+#define RC_FM ((uint32)1 << 8) /* direct fifo receive (pio) mode */ -+#define RC_AE ((uint32)3 << 16) /* address extension bits */ -+#define RC_AE_SHIFT 16 -+ -+/* receive descriptor table pointer */ -+#define RP_LD_MASK 0xfff /* last valid descriptor */ -+ -+/* receive channel status */ -+#define RS_CD_MASK 0x0fff /* current descriptor pointer */ -+#define RS_RS_MASK 0xf000 /* receive state */ -+#define RS_RS_SHIFT 12 -+#define RS_RS_DISABLED 0x0000 /* disabled */ -+#define RS_RS_ACTIVE 0x1000 /* active */ -+#define RS_RS_IDLE 0x2000 /* idle wait */ -+#define RS_RS_STOPPED 0x3000 /* reserved */ -+#define RS_RE_MASK 0xf0000 /* receive errors */ -+#define RS_RE_SHIFT 16 -+#define RS_RE_NOERR 0x00000 /* no error */ -+#define RS_RE_DPE 0x10000 /* descriptor protocol error */ -+#define RS_RE_DFO 0x20000 /* data fifo overflow */ -+#define RS_RE_BEBW 0x30000 /* bus error on buffer write */ -+#define RS_RE_BEDA 0x40000 /* bus error on descriptor access */ -+#define RS_AD_MASK 0xfff00000 /* active descriptor */ -+#define RS_AD_SHIFT 20 -+ -+/* fifoaddr */ -+#define FA_OFF_MASK 0xffff /* offset */ -+#define FA_SEL_MASK 0xf0000 /* select */ -+#define FA_SEL_SHIFT 16 -+#define FA_SEL_XDD 0x00000 /* transmit dma data */ -+#define FA_SEL_XDP 0x10000 /* transmit dma pointers */ -+#define FA_SEL_RDD 0x40000 /* receive dma data */ -+#define FA_SEL_RDP 0x50000 /* receive dma pointers */ -+#define FA_SEL_XFD 0x80000 /* transmit fifo data */ -+#define FA_SEL_XFP 0x90000 /* transmit fifo pointers */ -+#define FA_SEL_RFD 0xc0000 /* receive fifo data */ -+#define FA_SEL_RFP 0xd0000 /* receive fifo pointers */ -+#define FA_SEL_RSD 0xe0000 /* receive frame status data */ -+#define FA_SEL_RSP 0xf0000 /* receive frame status pointers */ -+ -+/* descriptor control flags */ -+#define CTRL_BC_MASK 0x1fff /* buffer byte count */ -+#define CTRL_AE ((uint32)3 << 16) /* address extension bits */ -+#define CTRL_AE_SHIFT 16 -+#define CTRL_EOT ((uint32)1 << 28) /* end of descriptor table */ -+#define CTRL_IOC ((uint32)1 << 29) /* interrupt on completion */ -+#define CTRL_EOF ((uint32)1 << 30) /* end of frame */ -+#define CTRL_SOF ((uint32)1 << 31) /* start of frame */ -+ -+/* control flags in the range [27:20] are core-specific and not defined here */ -+#define CTRL_CORE_MASK 0x0ff00000 -+ -+/* 64 bits addressing */ -+ -+/* dma registers per channel(xmt or rcv) */ -+typedef volatile struct { -+ uint32 control; /* enable, et al */ -+ uint32 ptr; /* last descriptor posted to chip */ -+ uint32 addrlow; /* descriptor ring base address low 32-bits (8K aligned) */ -+ uint32 addrhigh; /* descriptor ring base address bits 63:32 (8K aligned) */ -+ uint32 status0; /* current descriptor, xmt state */ -+ uint32 status1; /* active descriptor, xmt error */ -+} dma64regs_t; -+ -+typedef volatile struct { -+ dma64regs_t tx; /* dma64 tx channel */ -+ dma64regs_t rx; /* dma64 rx channel */ -+} dma64regp_t; -+ -+typedef volatile struct { /* diag access */ -+ uint32 fifoaddr; /* diag address */ -+ uint32 fifodatalow; /* low 32bits of data */ -+ uint32 fifodatahigh; /* high 32bits of data */ -+ uint32 pad; /* reserved */ -+} dma64diag_t; -+ -+/* -+ * DMA Descriptor -+ * Descriptors are only read by the hardware, never written back. -+ */ -+typedef volatile struct { -+ uint32 ctrl1; /* misc control bits & bufcount */ -+ uint32 ctrl2; /* buffer count and address extension */ -+ uint32 addrlow; /* memory address of the date buffer, bits 31:0 */ -+ uint32 addrhigh; /* memory address of the date buffer, bits 63:32 */ -+} dma64dd_t; -+ -+/* -+ * Each descriptor ring must be 8kB aligned, and fit within a contiguous 8kB physical addresss. -+ */ -+#define D64MAXRINGSZ 8192 -+#define D64RINGALIGN 8192 -+#define D64MAXDD (D64MAXRINGSZ / sizeof (dma64dd_t)) -+ -+/* transmit channel control */ -+#define D64_XC_XE 0x00000001 /* transmit enable */ -+#define D64_XC_SE 0x00000002 /* transmit suspend request */ -+#define D64_XC_LE 0x00000004 /* loopback enable */ -+#define D64_XC_FL 0x00000010 /* flush request */ -+#define D64_XC_AE 0x00030000 /* address extension bits */ -+#define D64_XC_AE_SHIFT 16 -+ -+/* transmit descriptor table pointer */ -+#define D64_XP_LD_MASK 0x00000fff /* last valid descriptor */ -+ -+/* transmit channel status */ -+#define D64_XS0_CD_MASK 0x00001fff /* current descriptor pointer */ -+#define D64_XS0_XS_MASK 0xf0000000 /* transmit state */ -+#define D64_XS0_XS_SHIFT 28 -+#define D64_XS0_XS_DISABLED 0x00000000 /* disabled */ -+#define D64_XS0_XS_ACTIVE 0x10000000 /* active */ -+#define D64_XS0_XS_IDLE 0x20000000 /* idle wait */ -+#define D64_XS0_XS_STOPPED 0x30000000 /* stopped */ -+#define D64_XS0_XS_SUSP 0x40000000 /* suspend pending */ -+ -+#define D64_XS1_AD_MASK 0x0001ffff /* active descriptor */ -+#define D64_XS1_XE_MASK 0xf0000000 /* transmit errors */ -+#define D64_XS1_XE_SHIFT 28 -+#define D64_XS1_XE_NOERR 0x00000000 /* no error */ -+#define D64_XS1_XE_DPE 0x10000000 /* descriptor protocol error */ -+#define D64_XS1_XE_DFU 0x20000000 /* data fifo underrun */ -+#define D64_XS1_XE_DTE 0x30000000 /* data transfer error */ -+#define D64_XS1_XE_DESRE 0x40000000 /* descriptor read error */ -+#define D64_XS1_XE_COREE 0x50000000 /* core error */ -+ -+/* receive channel control */ -+#define D64_RC_RE 0x00000001 /* receive enable */ -+#define D64_RC_RO_MASK 0x000000fe /* receive frame offset */ -+#define D64_RC_RO_SHIFT 1 -+#define D64_RC_FM 0x00000100 /* direct fifo receive (pio) mode */ -+#define D64_RC_AE 0x00030000 /* address extension bits */ -+#define D64_RC_AE_SHIFT 16 -+ -+/* receive descriptor table pointer */ -+#define D64_RP_LD_MASK 0x00000fff /* last valid descriptor */ -+ -+/* receive channel status */ -+#define D64_RS0_CD_MASK 0x00001fff /* current descriptor pointer */ -+#define D64_RS0_RS_MASK 0xf0000000 /* receive state */ -+#define D64_RS0_RS_SHIFT 28 -+#define D64_RS0_RS_DISABLED 0x00000000 /* disabled */ -+#define D64_RS0_RS_ACTIVE 0x10000000 /* active */ -+#define D64_RS0_RS_IDLE 0x20000000 /* idle wait */ -+#define D64_RS0_RS_STOPPED 0x30000000 /* stopped */ -+#define D64_RS0_RS_SUSP 0x40000000 /* suspend pending */ -+ -+#define D64_RS1_AD_MASK 0x0001ffff /* active descriptor */ -+#define D64_RS1_RE_MASK 0xf0000000 /* receive errors */ -+#define D64_RS1_RE_SHIFT 28 -+#define D64_RS1_RE_NOERR 0x00000000 /* no error */ -+#define D64_RS1_RE_DPO 0x10000000 /* descriptor protocol error */ -+#define D64_RS1_RE_DFU 0x20000000 /* data fifo overflow */ -+#define D64_RS1_RE_DTE 0x30000000 /* data transfer error */ -+#define D64_RS1_RE_DESRE 0x40000000 /* descriptor read error */ -+#define D64_RS1_RE_COREE 0x50000000 /* core error */ -+ -+/* fifoaddr */ -+#define D64_FA_OFF_MASK 0xffff /* offset */ -+#define D64_FA_SEL_MASK 0xf0000 /* select */ -+#define D64_FA_SEL_SHIFT 16 -+#define D64_FA_SEL_XDD 0x00000 /* transmit dma data */ -+#define D64_FA_SEL_XDP 0x10000 /* transmit dma pointers */ -+#define D64_FA_SEL_RDD 0x40000 /* receive dma data */ -+#define D64_FA_SEL_RDP 0x50000 /* receive dma pointers */ -+#define D64_FA_SEL_XFD 0x80000 /* transmit fifo data */ -+#define D64_FA_SEL_XFP 0x90000 /* transmit fifo pointers */ -+#define D64_FA_SEL_RFD 0xc0000 /* receive fifo data */ -+#define D64_FA_SEL_RFP 0xd0000 /* receive fifo pointers */ -+#define D64_FA_SEL_RSD 0xe0000 /* receive frame status data */ -+#define D64_FA_SEL_RSP 0xf0000 /* receive frame status pointers */ -+ -+/* descriptor control flags 1 */ -+#define D64_CTRL1_EOT ((uint32)1 << 28) /* end of descriptor table */ -+#define D64_CTRL1_IOC ((uint32)1 << 29) /* interrupt on completion */ -+#define D64_CTRL1_EOF ((uint32)1 << 30) /* end of frame */ -+#define D64_CTRL1_SOF ((uint32)1 << 31) /* start of frame */ -+ -+/* descriptor control flags 2 */ -+#define D64_CTRL2_BC_MASK 0x00007fff /* buffer byte count mask */ -+#define D64_CTRL2_AE 0x00030000 /* address extension bits */ -+#define D64_CTRL2_AE_SHIFT 16 -+ -+/* control flags in the range [27:20] are core-specific and not defined here */ -+#define D64_CTRL_CORE_MASK 0x0ff00000 -+ -+ -+#endif /* _sbhnddma_h_ */ diff -urN linux.old/drivers/parport/Config.in linux.dev/drivers/parport/Config.in --- linux.old/drivers/parport/Config.in 2006-04-27 18:04:38.000000000 +0200 +++ linux.dev/drivers/parport/Config.in 2006-04-27 19:24:19.000000000 +0200 -- 2.30.2