Date:2010-06-26 22:42:08 (4 years 4 months ago)
Author:nbd
Commit:4b7db99798885095b033f783fc43fd05f35ce99d
Message:remove the old broadcom wl driver for linux 2.4

git-svn-id: svn://svn.openwrt.org/openwrt/trunk@21947 3c298f89-4303-0410-b956-a3cf2f4a3e73
Files: package/broadcom-wl-old/Makefile (1 diff)
package/broadcom-wl-old/files/etc/hotplug.d/net/20-broadcom_wds (1 diff)
package/broadcom-wl-old/files/lib/wifi/broadcom.sh (1 diff)
package/broadcom-wl-old/patches/100-timer_fix.patch (1 diff)
package/broadcom-wl-old/src/driver/Makefile (1 diff)
package/broadcom-wl-old/src/driver/bcmip.h (1 diff)
package/broadcom-wl-old/src/driver/bcmutils.c (1 diff)
package/broadcom-wl-old/src/driver/bcmutils.h (1 diff)
package/broadcom-wl-old/src/driver/hnddma.c (1 diff)
package/broadcom-wl-old/src/driver/hnddma.h (1 diff)
package/broadcom-wl-old/src/driver/linux_osl.c (1 diff)
package/broadcom-wl-old/src/driver/linux_osl.h (1 diff)
package/broadcom-wl-old/src/driver/proto/802.11.h (1 diff)
package/broadcom-wl-old/src/driver/proto/802.11e.h (1 diff)
package/broadcom-wl-old/src/driver/proto/802.1d.h (1 diff)
package/broadcom-wl-old/src/driver/proto/802.3.h (1 diff)
package/broadcom-wl-old/src/driver/proto/bcmarp.h (1 diff)
package/broadcom-wl-old/src/driver/proto/bcmdhcp.h (1 diff)
package/broadcom-wl-old/src/driver/proto/bcmeth.h (1 diff)
package/broadcom-wl-old/src/driver/proto/bcmevent.h (1 diff)
package/broadcom-wl-old/src/driver/proto/bcmip.h (1 diff)
package/broadcom-wl-old/src/driver/proto/bcmtcp.h (1 diff)
package/broadcom-wl-old/src/driver/proto/bcmudp.h (1 diff)
package/broadcom-wl-old/src/driver/proto/eap.h (1 diff)
package/broadcom-wl-old/src/driver/proto/eapol.h (1 diff)
package/broadcom-wl-old/src/driver/proto/ethernet.h (1 diff)
package/broadcom-wl-old/src/driver/proto/vlan.h (1 diff)
package/broadcom-wl-old/src/driver/proto/wpa.h (1 diff)
package/broadcom-wl-old/src/driver/sbhnddma.h (1 diff)
package/broadcom-wl-old/src/include/bcmdefs.h (1 diff)
package/broadcom-wl-old/src/include/bcmutils.h (1 diff)
package/broadcom-wl-old/src/include/proto/802.11.h (1 diff)
package/broadcom-wl-old/src/include/proto/bcmeth.h (1 diff)
package/broadcom-wl-old/src/include/proto/bcmevent.h (1 diff)
package/broadcom-wl-old/src/include/proto/ethernet.h (1 diff)
package/broadcom-wl-old/src/include/proto/wpa.h (1 diff)
package/broadcom-wl-old/src/include/typedefs.h (1 diff)
package/broadcom-wl-old/src/include/wlioctl.h (1 diff)
package/broadcom-wl-old/src/include/wlutils.h (1 diff)
package/broadcom-wl-old/src/nvram/nvram_stub.c (1 diff)
package/broadcom-wl-old/src/wlc/Makefile (1 diff)
package/broadcom-wl-old/src/wlc/ioctl.c (1 diff)
package/broadcom-wl-old/src/wlc/wlc.c (1 diff)
package/broadcom-wl-old/src/wlcompat/Makefile (1 diff)
package/broadcom-wl-old/src/wlcompat/wlcompat.c (1 diff)

Change Details

package/broadcom-wl-old/Makefile
1#
2# Copyright (C) 2006-2010 OpenWrt.org
3#
4# This is free software, licensed under the GNU General Public License v2.
5# See /LICENSE for more information.
6#
7
8include $(TOPDIR)/rules.mk
9include $(INCLUDE_DIR)/kernel.mk
10
11PKG_NAME:=broadcom-wl
12PKG_VERSION:=4.150.10.5.3
13PKG_RELEASE:=8
14WLC_VERSION:=0.2
15
16PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2
17PKG_SOURCE_URL:=http://downloads.openwrt.org/sources
18PKG_MD5SUM:=cc615fd49719eea8bce5b2a8813783f3
19
20WL_WEXT=1
21
22include $(INCLUDE_DIR)/package.mk
23
24define Package/broadcom-wl-old/Default
25  SECTION:=kernel
26  CATEGORY:=Kernel modules
27  DEPENDS:=@PACKAGE_kmod-brcm-wl-old||PACKAGE_kmod-brcm-wl-mimo-old
28  SUBMENU:=Proprietary BCM43xx WiFi driver
29  SUBMENUDEP:=@TARGET_brcm_2_4||@TARGET_brcm47xx
30endef
31
32define KernelPackage/brcm-wl-old/Default
33  $(call Package/broadcom-wl-old/Default)
34  SECTION:=kernel
35  DEPENDS:=@TARGET_brcm_2_4 +wireless-tools
36  TITLE:=Kernel driver for BCM43xx chipsets
37  FILES:=$(PKG_BUILD_DIR)/driver/wl$(1).o
38  AUTOLOAD:=$(call AutoLoad,30,wl$(1))
39endef
40
41define KernelPackage/brcm-wl-old/Default/description
42 This package contains the proprietary wireless driver for the Broadcom
43 BCM43xx chipset.
44endef
45
46define KernelPackage/brcm-wl-old
47$(call KernelPackage/brcm-wl-old/Default,)
48  TITLE+= (normal version)
49endef
50
51define KernelPackage/brcm-wl-old/description
52$(call KernelPackage/brcm-wl-old/Default/description)
53endef
54
55define KernelPackage/brcm-wl-mimo-old
56$(call KernelPackage/brcm-wl-old/Default,_mimo)
57  TITLE+= (MIMO version)
58endef
59
60define KernelPackage/brcm-wl-mimo-old/description
61$(call KernelPackage/brcm-wl-old/Default/description)
62endef
63
64define KernelPackage/wlcompat/Default
65  $(call KernelPackage/brcm-wl-old/Default,)
66  TITLE:=Kernel driver for BCM43xx chipsets
67  FILES:=$(PKG_BUILD_DIR)/wlcompat/wlcompat$(1).o
68endef
69
70define KernelPackage/wlcompat
71$(call KernelPackage/wlcompat/Default,)
72  AUTOLOAD:=$(call AutoLoad,50,wlcompat)
73endef
74
75define KernelPackage/wlcompat/description
76 This package contains a wrapper module, that provides Wireless Extension
77 support for the proprietary Broadcom wl module.
78endef
79
80define KernelPackage/wlcompat-debug
81$(call KernelPackage/wlcompat/Default,-debug)
82  TITLE+= (debug)
83  AUTOLOAD:=
84endef
85
86define KernelPackage/wlcompat-debug/description
87$(call KernelPackage/wlcompat/description)
88 This is the debugging version.
89endef
90
91define Package/wlc-old
92$(call Package/broadcom-wl-old/Default)
93  TITLE:=wl driver setup utility
94endef
95
96define Package/wlc-old/description
97 This package contains an utility for initializing the proprietary Broadcom
98 wl driver.
99endef
100
101define Package/wl-old
102$(call Package/broadcom-wl-old/Default)
103  TITLE:=Proprietary Broadcom wl driver config utility
104endef
105
106define Package/wl-old/description
107 This package contains the proprietary utility (wl) for configuring the
108 proprietary Broadcom wl driver.
109endef
110
111define Package/nas-old
112$(call Package/broadcom-wl-old/Default)
113  TITLE:=Proprietary Broadcom WPA/WPA2 authenticator
114endef
115
116define Package/nas-old/description
117 This package contains the proprietary WPA/WPA2 authenticator (nas) for the
118 proprietary Broadcom wl driver.
119endef
120
121MAKE_KMOD := $(MAKE) -C "$(LINUX_DIR)" \
122        CROSS_COMPILE="$(TARGET_CROSS)" \
123        ARCH="$(LINUX_KARCH)" \
124        PATH="$(TARGET_PATH)" \
125        SUBDIRS="$(PKG_BUILD_DIR)/kmod"
126
127define Build/Prepare
128    $(call Build/Prepare/Default)
129    $(CP) src/* $(PKG_BUILD_DIR)/
130endef
131
132define Build/Compile
133    # Compile the kernel part
134    $(MAKE_KMOD) \
135        SUBDIRS="$(PKG_BUILD_DIR)/driver" \
136        modules
137    $(MAKE_KMOD) \
138        SUBDIRS="$(PKG_BUILD_DIR)/driver" \
139        MOD_NAME="_mimo" \
140        modules
141    $(MAKE_KMOD) \
142        SUBDIRS="$(PKG_BUILD_DIR)/wlcompat" \
143        $(if $(WL_WEXT),WL_WEXT=1) \
144        modules
145    $(MAKE_KMOD) \
146        SUBDIRS="$(PKG_BUILD_DIR)/wlcompat" \
147        DEBUG=1 \
148        $(if $(WL_WEXT),WL_WEXT=1) \
149        modules
150
151    # NVRAM stub
152    $(TARGET_CC) $(TARGET_CFLAGS) -c -o $(PKG_BUILD_DIR)/nvram/nvram_stub.o $(PKG_BUILD_DIR)/nvram/nvram_stub.c
153
154    # Compile wlc
155    $(MAKE) -C $(PKG_BUILD_DIR)/wlc \
156        $(TARGET_CONFIGURE_OPTS) \
157        CFLAGS="$(TARGET_CFLAGS)" \
158        all
159
160    # Compile libshared
161    $(MAKE) -C $(PKG_BUILD_DIR)/router/shared \
162        $(TARGET_CONFIGURE_OPTS) \
163        CFLAGS="$(TARGET_CFLAGS) -I. -I$(PKG_BUILD_DIR)/include -Dlinux=1" \
164        all
165    $(TARGET_CC) -o $(PKG_BUILD_DIR)/nas \
166        $(PKG_BUILD_DIR)/nas_exe.o \
167        $(PKG_BUILD_DIR)/nvram/nvram_stub.o \
168        $(TARGET_LDFLAGS) \
169        $(PKG_BUILD_DIR)/router/shared/libshared.a
170    $(TARGET_CC) -o $(PKG_BUILD_DIR)/wl $(PKG_BUILD_DIR)/wl_exe.o
171endef
172
173define Build/InstallDev
174    $(INSTALL_DIR) $(1)/usr/lib
175    $(CP) $(PKG_BUILD_DIR)/router/shared/libshared.a $(1)/usr/lib/
176endef
177
178define Package/wlc-old/install
179    $(CP) ./files/* $(1)/
180    $(INSTALL_DIR) $(1)/sbin
181    $(INSTALL_BIN) $(PKG_BUILD_DIR)/wlc/wlc $(1)/sbin/
182endef
183
184define Package/wl-old/install
185    $(INSTALL_DIR) $(1)/usr/sbin
186    $(INSTALL_BIN) $(PKG_BUILD_DIR)/wl $(1)/usr/sbin/
187endef
188
189define Package/nas-old/install
190    $(INSTALL_DIR) $(1)/usr/sbin
191    $(INSTALL_BIN) $(PKG_BUILD_DIR)/nas $(1)/usr/sbin/
192    ln -sf nas $(1)/usr/sbin/nas4not
193    ln -sf nas $(1)/usr/sbin/nas4wds
194endef
195
196$(eval $(call KernelPackage,brcm-wl-old))
197$(eval $(call KernelPackage,brcm-wl-mimo-old))
198$(eval $(call KernelPackage,wlcompat))
199$(eval $(call KernelPackage,wlcompat-debug))
200$(eval $(call BuildPackage,wlc-old))
201$(eval $(call BuildPackage,wl-old))
202$(eval $(call BuildPackage,nas-old))
package/broadcom-wl-old/files/etc/hotplug.d/net/20-broadcom_wds
1include /lib/wifi
2
3setup_broadcom_wds() {
4    local iface="$1"
5    local remote="$(wlc ifname "$iface" wdsmac)"
6
7    [ -z "$remote" ] && return
8
9    config_cb() {
10        [ -z "$CONFIG_SECTION" ] && return
11
12        config_get type "$CONFIG_SECTION" TYPE
13        [ "$type" = "wifi-iface" ] || return
14
15        config_get network "$CONFIG_SECTION" network
16        [ -z "$network" ] && return
17
18        config_get addr "$CONFIG_SECTION" bssid
19        addr=$(echo "$addr" | tr 'A-F' 'a-f')
20        [ "$addr" = "$remote" ] && {
21            local cfg="$CONFIG_SECTION"
22
23            include /lib/network
24            scan_interfaces
25
26            setup_interface "$iface" "$network"
27
28            config_get encryption "$cfg" encryption
29            config_get key "$cfg" key
30            config_get ssid "$cfg" ssid
31
32            [ "$encryption" != "none" ] && {
33                sleep 5
34                case "$encryption" in
35                    psk|PSK)
36                        nas4not "$network" "$iface" up auto tkip psk "$key" "$ssid"
37                        ;;
38                    psk2|PSK2)
39                        nas4not "$network" "$iface" up auto aes psk "$key" "$ssid"
40                        ;;
41                    psk+psk2|psk2+psk|PSK+PSK2|PSK2+PSK)
42                        nas4not "$network" "$iface" up auto aes+tkip psk "$key" "$ssid"
43                        ;;
44                    *)
45                        nas4not lan "$iface" up auto aes "$encryption" "$key" "$ssid"
46                        ;;
47                    esac
48            }
49        }
50    }
51
52    config_load wireless
53}
54
55case "$ACTION" in
56    add|register)
57        [ "${INTERFACE%%0.*}" = wds ] && setup_broadcom_wds "$INTERFACE"
58    ;;
59esac
package/broadcom-wl-old/files/lib/wifi/broadcom.sh
1append DRIVERS "broadcom"
2
3scan_broadcom() {
4    local device="$1"
5    local wds
6    local adhoc sta apmode mon
7    local adhoc_if sta_if ap_if mon_if
8    local _c=0
9
10    config_get vifs "$device" vifs
11    for vif in $vifs; do
12        config_get mode "$vif" mode
13        _c=$(($_c + 1))
14        case "$mode" in
15            adhoc)
16                adhoc=1
17                adhoc_if="$vif"
18            ;;
19            sta)
20                sta=1
21                sta_if="$vif"
22            ;;
23            ap)
24                apmode=1
25                ap_if="${ap_if:+$ap_if }$vif"
26            ;;
27            wds)
28                config_get addr "$vif" bssid
29                [ -z "$addr" ] || {
30                    addr=$(echo "$addr" | tr 'A-F' 'a-f')
31                    append wds "$addr"
32                }
33            ;;
34            monitor)
35                mon=1
36                mon_if="$vif"
37            ;;
38            *) echo "$device($vif): Invalid mode";;
39        esac
40    done
41    config_set "$device" wds "$wds"
42
43    local _c=
44    for vif in ${adhoc_if:-$sta_if $ap_if $mon_if}; do
45        config_set "$vif" ifname "${device}${_c:+.$_c}"
46        _c=$((${_c:-0} + 1))
47    done
48    config_set "$device" vifs "${adhoc_if:-$sta_if $ap_if $mon_if}"
49
50    ifdown="down"
51    for vif in 0 1 2 3; do
52        append ifdown "vif $vif" "$N"
53        append ifdown "enabled 0" "$N"
54    done
55
56    ap=1
57    infra=1
58    if [ "$_c" -gt 1 ]; then
59        mssid=1
60    else
61        mssid=
62    fi
63    apsta=0
64    radio=1
65    monitor=0
66    passive=0
67    case "$adhoc:$sta:$apmode:$mon" in
68        1*)
69            ap=0
70            mssid=
71            infra=0
72        ;;
73        :1:1:)
74            apsta=1
75            wet=1
76        ;;
77        :1::)
78            wet=1
79            ap=0
80            mssid=
81        ;;
82        :::1)
83            wet=1
84            ap=0
85            mssid=
86            monitor=1
87            passive=1
88        ;;
89        ::)
90            radio=0
91        ;;
92    esac
93}
94
95disable_broadcom() {
96    local device="$1"
97    set_wifi_down "$device"
98    wlc ifname "$device" down
99    (
100        include /lib/network
101
102        # make sure the interfaces are down and removed from all bridges
103        for dev in $device ${device}.1 ${device}.2 ${device}.3; do
104            ifconfig "$dev" down 2>/dev/null >/dev/null && {
105                unbridge "$dev"
106            }
107        done
108    )
109    true
110}
111
112enable_broadcom() {
113    local device="$1"
114    local _c
115    config_get channel "$device" channel
116    config_get country "$device" country
117    config_get maxassoc "$device" maxassoc
118    config_get wds "$device" wds
119    config_get vifs "$device" vifs
120    config_get distance "$device" distance
121    config_get slottime "$device" slottime
122    config_get rxantenna "$device" rxantenna
123    config_get txantenna "$device" txantenna
124    config_get_bool frameburst "$device" frameburst
125    config_get macfilter "$device" macfilter
126    config_get maclist "$device" maclist
127    config_get macaddr "$device" macaddr
128    config_get txpower "$device" txpower
129    config_get frag "$device" frag
130    config_get rts "$device" rts
131    config_get hwmode "$device" hwmode
132    local vif_pre_up vif_post_up vif_do_up vif_txpower
133    local doth=0
134    local wmm=0
135
136    _c=0
137    nas="$(which nas)"
138    nas_cmd=
139    if_up=
140
141    [ -z "$slottime" ] && {
142        [ -n "$distance" ] && {
143            # slottime = 9 + (distance / 150) + (distance % 150 ? 1 : 0)
144            slottime="$((9 + ($distance / 150) + 1 - (150 - ($distance % 150)) / 150 ))"
145        }
146    } || {
147        slottime="${slottime:--1}"
148    }
149
150    case "$macfilter" in
151        allow|2)
152            macfilter=2;
153        ;;
154        deny|1)
155            macfilter=1;
156        ;;
157        disable|none|0)
158            macfilter=0;
159        ;;
160    esac
161
162    case "$hwmode" in
163        *b) hwmode=0;;
164        *bg) hwmode=1;;
165        *g) hwmode=2;;
166        *gst) hwmode=4;;
167        *lrs) hwmode=5;;
168        *) hwmode=1;;
169    esac
170
171    for vif in $vifs; do
172        config_get vif_txpower "$vif" txpower
173
174        config_get mode "$vif" mode
175        append vif_pre_up "vif $_c" "$N"
176        append vif_post_up "vif $_c" "$N"
177        append vif_do_up "vif $_c" "$N"
178
179        config_get_bool wmm "$vif" wmm "$wmm"
180        config_get_bool doth "$vif" doth "$doth"
181
182        [ "$mode" = "sta" ] || {
183            config_get_bool hidden "$vif" hidden 0
184            append vif_pre_up "closed $hidden" "$N"
185            config_get_bool isolate "$vif" isolate 0
186            append vif_pre_up "ap_isolate $isolate" "$N"
187        }
188
189        wsec_r=0
190        eap_r=0
191        wsec=0
192        auth=0
193        nasopts=
194        config_get enc "$vif" encryption
195        case "$enc" in
196            *WEP*|*wep*)
197                wsec_r=1
198                wsec=1
199                defkey=1
200                config_get key "$vif" key
201                case "$enc" in
202                    *shared*) append vif_do_up "wepauth 1" "$N";;
203                    *) append vif_do_up "wepauth 0" "$N";;
204                esac
205                case "$key" in
206                    [1234])
207                        defkey="$key"
208                        for knr in 1 2 3 4; do
209                            config_get k "$vif" key$knr
210                            [ -n "$k" ] || continue
211                            [ "$defkey" = "$knr" ] && def="=" || def=""
212                            append vif_do_up "wepkey $def$knr,$k" "$N"
213                        done
214                    ;;
215                    "");;
216                    *) append vif_do_up "wepkey =1,$key" "$N";;
217                esac
218            ;;
219            *psk*|*PSK*)
220                wsec_r=1
221                config_get key "$vif" key
222                case "$enc" in
223                    wpa*+wpa2*|WPA*+WPA2*|*psk+*psk2|*PSK+*PSK2) auth=132; wsec=6;;
224                    wpa2*|WPA2*|*PSK2|*psk2) auth=128; wsec=4;;
225                    *aes|*AES) auth=4; wsec=4;;
226                    *) auth=4; wsec=2;;
227                esac
228                eval "${vif}_key=\"\$key\""
229                nasopts="-k \"\$${vif}_key\""
230            ;;
231            *wpa*|*WPA*)
232                wsec_r=1
233                eap_r=1
234                config_get key "$vif" key
235                config_get server "$vif" server
236                config_get port "$vif" port
237                case "$enc" in
238                    wpa*+wpa2*|WPA*+WPA2*) auth=66; wsec=6;;
239                    wpa2*|WPA2*) auth=64; wsec=4;;
240                    *) auth=2; wsec=2;;
241                esac
242                eval "${vif}_key=\"\$key\""
243                nasopts="-r \"\$${vif}_key\" -h $server -p ${port:-1812}"
244            ;;
245        esac
246        append vif_do_up "wsec $wsec" "$N"
247        append vif_do_up "wpa_auth $auth" "$N"
248        append vif_do_up "wsec_restrict $wsec_r" "$N"
249        append vif_do_up "eap_restrict $eap_r" "$N"
250
251        config_get ssid "$vif" ssid
252        append vif_post_up "vlan_mode 0" "$N"
253        append vif_post_up "ssid $ssid" "$N"
254        append vif_do_up "ssid $ssid" "$N"
255
256        [ "$mode" = "monitor" ] && {
257            append vif_post_up "monitor $monitor" "$N"
258            append vif_post_up "passive $passive" "$N"
259        }
260
261        [ "$mode" = "adhoc" ] && {
262            config_get bssid "$vif" bssid
263            [ -n "$bssid" ] && {
264                append vif_pre_up "des_bssid $bssid" "$N"
265                append vif_pre_up "allow_mode 1" "$N"
266            }
267        } || append vif_pre_up "allow_mode 0" "$N"
268
269        append vif_post_up "enabled 1" "$N"
270
271        config_get ifname "$vif" ifname
272        #append if_up "ifconfig $ifname up" ";$N"
273
274        local net_cfg bridge
275        net_cfg="$(find_net_config "$vif")"
276        [ -z "$net_cfg" ] || {
277            bridge="$(bridge_interface "$net_cfg")"
278            append if_up "set_wifi_up '$vif' '$ifname'" ";$N"
279            append if_up "start_net '$ifname' '$net_cfg' \$(wlc ifname '$ifname' bssid)" ";$N"
280        }
281        [ -z "$nasopts" ] || {
282            eval "${vif}_ssid=\"\$ssid\""
283            nas_mode="-A"
284            use_nas=1
285            [ "$mode" = "sta" ] && {
286                nas_mode="-S"
287                [ -z "$bridge" ] || {
288                    append vif_post_up "supplicant 1" "$N"
289                    append vif_post_up "passphrase $key" "$N"
290
291                    use_nas=0
292                }
293            }
294            [ -z "$nas" -o "$use_nas" = "0" ] || {
295                nas_cmd="${nas_cmd:+$nas_cmd$N}start-stop-daemon -S -b -p /var/run/nas.$ifname.pid -x $nas -- -P /var/run/nas.$ifname.pid -H 34954 ${bridge:+ -l $bridge} -i $ifname $nas_mode -m $auth -w $wsec -s \"\$${vif}_ssid\" -g 3600 $nasopts"
296            }
297        }
298        _c=$(($_c + 1))
299    done
300    killall -KILL nas >&- 2>&-
301    wlc ifname "$device" stdin <<EOF
302$ifdown
303
304gmode ${hwmode:-1}
305apsta $apsta
306ap $ap
307${mssid:+mssid $mssid}
308infra $infra
309${wet:+wet 1}
310802.11d 0
311802.11h ${doth:-0}
312wme ${wmm:-0}
313rxant ${rxantenna:-3}
314txant ${txantenna:-3}
315fragthresh ${frag:-2346}
316rtsthresh ${rts:-2347}
317monitor ${monitor:-0}
318passive ${passive:-0}
319
320radio ${radio:-1}
321macfilter ${macfilter:-0}
322maclist ${maclist:-none}
323wds none
324${wds:+wds $wds}
325country ${country:-IL0}
326${channel:+channel $channel}
327maxassoc ${maxassoc:-128}
328slottime ${slottime:--1}
329${frameburst:+frameburst $frameburst}
330
331$vif_pre_up
332up
333$vif_post_up
334EOF
335    eval "$if_up"
336    wlc ifname "$device" stdin <<EOF
337$vif_do_up
338EOF
339
340    # use vif_txpower (from last wifi-iface) instead of txpower (from
341    # wifi-device) if the latter does not exist
342    txpower=${txpower:-$vif_txpower}
343    [ -z "$txpower" ] || iwconfig $device txpower ${txpower}dBm
344
345    eval "$nas_cmd"
346}
347
348
349detect_broadcom() {
350    local i=-1
351
352    while [ -f /proc/net/wl$((++i)) ]; do
353        config_get type wl${i} type
354        [ "$type" = broadcom ] && continue
355        cat <<EOF
356config wifi-device wl${i}
357    option type broadcom
358    option channel 5
359
360    # REMOVE THIS LINE TO ENABLE WIFI:
361    option disabled 1
362
363config wifi-iface
364    option device wl${i}
365    option network lan
366    option mode ap
367    option ssid OpenWrt${i#0}
368    option encryption none
369
370EOF
371    done
372}
package/broadcom-wl-old/patches/100-timer_fix.patch
1+++ b/router/shared/linux_timer.c
2@@ -94,6 +94,7 @@ typedef long uclock_t;
3 #define TFLAG_NONE 0
4 #define TFLAG_CANCELLED (1<<0)
5 #define TFLAG_DELETED (1<<1)
6+#define TFLAG_QUEUED (1<<2)
7
8 struct event {
9     struct timeval it_interval;
10@@ -207,6 +208,7 @@ int timer_create(
11
12     event_freelist = event->next;
13     event->next = NULL;
14+ event->flags &= ~TFLAG_QUEUED;
15
16     check_event_queue();
17
18@@ -387,6 +389,7 @@ int timer_settime
19     }
20
21     event->flags &= ~TFLAG_CANCELLED;
22+ event->flags |= TFLAG_QUEUED;
23
24     unblock_timer();
25
26@@ -502,7 +505,15 @@ static void alarm_handler(int i)
27         (*(event->func))((timer_t) event, (int)event->arg);
28
29         /* If the event has been cancelled, do NOT put it back on the queue. */
30- if (!(event->flags & TFLAG_CANCELLED)) {
31+ /* Check for TFLAG_QUEUED is to avoid pathologic case, when after
32+ * dequeueing event handler deletes its own timer and allocates new one
33+ * which (at least in some cases) gets the same pointer and thus its
34+ * 'flags' will be rewritten, most notably TFLAG_CANCELLED, and, to
35+ * complete the disaster, it will be queued. alarm_handler tries to
36+ * enqueue 'event' (which is on the same memory position as newly
37+ * allocated timer), which results in queueing the same pointer once
38+ * more. And this way, loop in event queue is created. */
39+ if ( !(event->flags & TFLAG_CANCELLED) && !(event->flags & TFLAG_QUEUED) ) {
40
41             /* if the event is a recurring event, reset the timer and
42              * find its correct place in the sorted list of events.
43@@ -545,6 +556,7 @@ static void alarm_handler(int i)
44                 /* link our new event into the pending event queue. */
45                 event->next = *ppevent;
46                 *ppevent = event;
47+ event->flags |= TFLAG_QUEUED;
48             } else {
49                 /* there is no interval, so recycle the event structure.
50                  * timer_delete((timer_t) event);
package/broadcom-wl-old/src/driver/Makefile
1#
2# Makefile for the Broadcom wl driver
3#
4# Copyright 2004, Broadcom Corporation
5# All Rights Reserved.
6#
7# THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
8# KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
9# SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
10# FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
11#
12
13EXTRA_CFLAGS += -I$(TOPDIR)/arch/mips/bcm947xx/include -DBCMDRIVER=1 -DBCMDMA64=1
14
15O_TARGET := wl$(MOD_NAME).o
16
17obj-y := wl_mod$(MOD_NAME).o
18obj-y += bcmutils.o hnddma.o linux_osl.o
19
20obj-m := $(O_TARGET)
21
22wl_mod$(MOD_NAME).o: wl_apsta$(MOD_NAME).o
23    perl -ne 's,eth%d,wl%d\x00,g,print' < $< > $@
24
25modules: wl$(MOD_NAME).o
26
27include $(TOPDIR)/Rules.make
package/broadcom-wl-old/src/driver/bcmip.h
1/*
2 * Copyright 2006, Broadcom Corporation
3 * All Rights Reserved.
4 *
5 * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
6 * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
7 * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
8 * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
9 *
10 * Fundamental constants relating to IP Protocol
11 *
12 */
13
14#ifndef _bcmip_h_
15#define _bcmip_h_
16
17/* IPV4 and IPV6 common */
18#define IP_VER_OFFSET 0x0 /* offset to version field */
19#define IP_VER_MASK 0xf0 /* version mask */
20#define IP_VER_SHIFT 4 /* version shift */
21#define IP_VER_4 4 /* version number for IPV4 */
22#define IP_VER_6 6 /* version number for IPV6 */
23
24#define IP_VER(ip_body) \
25    ((((uint8 *)(ip_body))[IP_VER_OFFSET] & IP_VER_MASK) >> IP_VER_SHIFT)
26
27#define IP_PROT_ICMP 0x1 /* ICMP protocol */
28#define IP_PROT_TCP 0x6 /* TCP protocol */
29#define IP_PROT_UDP 0x11 /* UDP protocol type */
30
31/* IPV4 field offsets */
32#define IPV4_VER_HL_OFFSET 0 /* version and ihl byte offset */
33#define IPV4_TOS_OFFSET 1 /* type of service offset */
34#define IPV4_PROT_OFFSET 9 /* protocol type offset */
35#define IPV4_CHKSUM_OFFSET 10 /* IP header checksum offset */
36#define IPV4_SRC_IP_OFFSET 12 /* src IP addr offset */
37#define IPV4_DEST_IP_OFFSET 16 /* dest IP addr offset */
38
39/* IPV4 field decodes */
40#define IPV4_VER_MASK 0xf0 /* IPV4 version mask */
41#define IPV4_VER_SHIFT 4 /* IPV4 version shift */
42
43#define IPV4_HLEN_MASK 0x0f /* IPV4 header length mask */
44#define IPV4_HLEN(ipv4_body) (4 * (((uint8 *)(ipv4_body))[IPV4_VER_HL_OFFSET] & IPV4_HLEN_MASK))
45
46#define IPV4_ADDR_LEN 4 /* IPV4 address length */
47
48#define IPV4_ADDR_NULL(a) ((((uint8 *)(a))[0] | ((uint8 *)(a))[1] | \
49                  ((uint8 *)(a))[2] | ((uint8 *)(a))[3]) == 0)
50
51#define IPV4_TOS_DSCP_MASK 0xfc /* DiffServ codepoint mask */
52#define IPV4_TOS_DSCP_SHIFT 2 /* DiffServ codepoint shift */
53
54#define IPV4_TOS(ipv4_body) (((uint8 *)(ipv4_body))[IPV4_TOS_OFFSET])
55
56#define IPV4_TOS_PREC_MASK 0xe0 /* Historical precedence mask */
57#define IPV4_TOS_PREC_SHIFT 5 /* Historical precedence shift */
58
59#define IPV4_TOS_LOWDELAY 0x10 /* Lowest delay requested */
60#define IPV4_TOS_THROUGHPUT 0x8 /* Best throughput requested */
61#define IPV4_TOS_RELIABILITY 0x4 /* Most reliable delivery requested */
62
63#define IPV4_PROT(ipv4_body) (((uint8 *)(ipv4_body))[IPV4_PROT_OFFSET])
64
65#define IPV4_ADDR_STR_LEN 16 /* Max IP address length in string format */
66
67/* IPV6 field offsets */
68#define IPV6_PAYLOAD_LEN_OFFSET 4 /* payload length offset */
69#define IPV6_NEXT_HDR_OFFSET 6 /* next header/protocol offset */
70#define IPV6_HOP_LIMIT_OFFSET 7 /* hop limit offset */
71#define IPV6_SRC_IP_OFFSET 8 /* src IP addr offset */
72#define IPV6_DEST_IP_OFFSET 24 /* dst IP addr offset */
73
74/* IPV6 field decodes */
75#define IPV6_TRAFFIC_CLASS(ipv6_body) \
76    (((((uint8 *)(ipv6_body))[0] & 0x0f) << 4) | \
77     ((((uint8 *)(ipv6_body))[1] & 0xf0) >> 4))
78
79#define IPV6_FLOW_LABEL(ipv6_body) \
80    (((((uint8 *)(ipv6_body))[1] & 0x0f) << 16) | \
81     (((uint8 *)(ipv6_body))[2] << 8) | \
82     (((uint8 *)(ipv6_body))[3]))
83
84#define IPV6_PAYLOAD_LEN(ipv6_body) \
85    ((((uint8 *)(ipv6_body))[IPV6_PAYLOAD_LEN_OFFSET + 0] << 8) | \
86     ((uint8 *)(ipv6_body))[IPV6_PAYLOAD_LEN_OFFSET + 1])
87
88#define IPV6_NEXT_HDR(ipv6_body) \
89    (((uint8 *)(ipv6_body))[IPV6_NEXT_HDR_OFFSET])
90
91#define IPV6_PROT(ipv6_body) IPV6_NEXT_HDR(ipv6_body)
92
93#define IPV6_ADDR_LEN 16 /* IPV6 address length */
94
95/* IPV4 TOS or IPV6 Traffic Classifier or 0 */
96#define IP_TOS(ip_body) \
97    (IP_VER(ip_body) == IP_VER_4 ? IPV4_TOS(ip_body) : \
98     IP_VER(ip_body) == IP_VER_6 ? IPV6_TRAFFIC_CLASS(ip_body) : 0)
99
100#endif /* _bcmip_h_ */
package/broadcom-wl-old/src/driver/bcmutils.c
1/*
2 * Driver O/S-independent utility routines
3 *
4 * Copyright 2007, Broadcom Corporation
5 * All Rights Reserved.
6 *
7 * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
8 * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
9 * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
10 * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
11 */
12
13#include <typedefs.h>
14#include <bcmdefs.h>
15#include <stdarg.h>
16#include "bcmutils.h"
17#include <osl.h>
18#include <sbutils.h>
19#include <bcmnvram.h>
20#include <bcmendian.h>
21#include <bcmdevs.h>
22#include "proto/ethernet.h"
23#include "proto/vlan.h"
24#include "proto/bcmip.h"
25#include "proto/bcmtcp.h"
26#include "proto/802.1d.h"
27
28#ifdef BCMPERFSTATS
29#include <bcmperf.h>
30#endif
31
32#if 0
33/* nvram vars cache */
34static char *nvram_vars = NULL;
35static int vars_len = -1;
36#endif
37
38/* copy a pkt buffer chain into a buffer */
39uint
40pktcopy (osl_t * osh, void *p, uint offset, int len, uchar * buf)
41{
42  uint n, ret = 0;
43
44  if (len < 0)
45    len = 4096; /* "infinite" */
46
47  /* skip 'offset' bytes */
48  for (; p && offset; p = PKTNEXT (osh, p))
49    {
50      if (offset < (uint) PKTLEN (osh, p))
51    break;
52      offset -= PKTLEN (osh, p);
53    }
54
55  if (!p)
56    return 0;
57
58  /* copy the data */
59  for (; p && len; p = PKTNEXT (osh, p))
60    {
61      n = MIN ((uint) PKTLEN (osh, p) - offset, (uint) len);
62      bcopy (PKTDATA (osh, p) + offset, buf, n);
63      buf += n;
64      len -= n;
65      ret += n;
66      offset = 0;
67    }
68
69  return ret;
70}
71
72/* return total length of buffer chain */
73uint
74pkttotlen (osl_t * osh, void *p)
75{
76  uint total;
77
78  total = 0;
79  for (; p; p = PKTNEXT (osh, p))
80    total += PKTLEN (osh, p);
81  return (total);
82}
83
84/* return the last buffer of chained pkt */
85void *
86pktlast (osl_t * osh, void *p)
87{
88  for (; PKTNEXT (osh, p); p = PKTNEXT (osh, p))
89    ;
90
91  return (p);
92}
93
94
95/*
96 * osl multiple-precedence packet queue
97 * hi_prec is always >= the number of the highest non-empty precedence
98 */
99void *
100pktq_penq (struct pktq *pq, int prec, void *p)
101{
102  struct pktq_prec *q;
103
104  ASSERT (prec >= 0 && prec < pq->num_prec);
105  ASSERT (PKTLINK (p) == NULL); /* queueing chains not allowed */
106
107  ASSERT (!pktq_full (pq));
108  ASSERT (!pktq_pfull (pq, prec));
109
110  q = &pq->q[prec];
111
112  if (q->head)
113    PKTSETLINK (q->tail, p);
114  else
115    q->head = p;
116
117  q->tail = p;
118  q->len++;
119
120  pq->len++;
121
122  if (pq->hi_prec < prec)
123    pq->hi_prec = (uint8) prec;
124
125  return p;
126}
127
128void *
129pktq_penq_head (struct pktq *pq, int prec, void *p)
130{
131  struct pktq_prec *q;
132
133  ASSERT (prec >= 0 && prec < pq->num_prec);
134  ASSERT (PKTLINK (p) == NULL); /* queueing chains not allowed */
135
136  ASSERT (!pktq_full (pq));
137  ASSERT (!pktq_pfull (pq, prec));
138
139  q = &pq->q[prec];
140
141  if (q->head == NULL)
142    q->tail = p;
143
144  PKTSETLINK (p, q->head);
145  q->head = p;
146  q->len++;
147
148  pq->len++;
149
150  if (pq->hi_prec < prec)
151    pq->hi_prec = (uint8) prec;
152
153  return p;
154}
155
156void *
157pktq_pdeq (struct pktq *pq, int prec)
158{
159  struct pktq_prec *q;
160  void *p;
161
162  ASSERT (prec >= 0 && prec < pq->num_prec);
163
164  q = &pq->q[prec];
165
166  if ((p = q->head) == NULL)
167    return NULL;
168
169  if ((q->head = PKTLINK (p)) == NULL)
170    q->tail = NULL;
171
172  q->len--;
173
174  pq->len--;
175
176  PKTSETLINK (p, NULL);
177
178  return p;
179}
180
181void *
182pktq_pdeq_tail (struct pktq *pq, int prec)
183{
184  struct pktq_prec *q;
185  void *p, *prev;
186
187  ASSERT (prec >= 0 && prec < pq->num_prec);
188
189  q = &pq->q[prec];
190
191  if ((p = q->head) == NULL)
192    return NULL;
193
194  for (prev = NULL; p != q->tail; p = PKTLINK (p))
195    prev = p;
196
197  if (prev)
198    PKTSETLINK (prev, NULL);
199  else
200    q->head = NULL;
201
202  q->tail = prev;
203  q->len--;
204
205  pq->len--;
206
207  return p;
208}
209
210void
211pktq_pflush (osl_t * osh, struct pktq *pq, int prec, bool dir)
212{
213  struct pktq_prec *q;
214  void *p;
215
216  q = &pq->q[prec];
217  p = q->head;
218  while (p)
219    {
220      q->head = PKTLINK (p);
221      PKTSETLINK (p, NULL);
222      PKTFREE (osh, p, dir);
223      q->len--;
224      pq->len--;
225      p = q->head;
226    }
227  ASSERT (q->len == 0);
228  q->tail = NULL;
229}
230
231#if 0
232bool
233pktq_pdel (struct pktq *pq, void *pktbuf, int prec)
234{
235  struct pktq_prec *q;
236  void *p;
237
238  ASSERT (prec >= 0 && prec < pq->num_prec);
239
240  if (!pktbuf)
241    return FALSE;
242
243  q = &pq->q[prec];
244
245  if (q->head == pktbuf)
246    {
247      if ((q->head = PKTLINK (pktbuf)) == NULL)
248    q->tail = NULL;
249    }
250  else
251    {
252      for (p = q->head; p && PKTLINK (p) != pktbuf; p = PKTLINK (p))
253    ;
254      if (p == NULL)
255    return FALSE;
256
257      PKTSETLINK (p, PKTLINK (pktbuf));
258      if (q->tail == pktbuf)
259    q->tail = p;
260    }
261
262  q->len--;
263  pq->len--;
264  PKTSETLINK (pktbuf, NULL);
265  return TRUE;
266}
267#endif
268
269void
270pktq_init (struct pktq *pq, int num_prec, int max_len)
271{
272  int prec;
273
274  ASSERT (num_prec > 0 && num_prec <= PKTQ_MAX_PREC);
275
276  /* pq is variable size; only zero out what's requested */
277  bzero (pq,
278     OFFSETOF (struct pktq, q) + (sizeof (struct pktq_prec) * num_prec));
279
280  pq->num_prec = (uint16) num_prec;
281
282  pq->max = (uint16) max_len;
283
284  for (prec = 0; prec < num_prec; prec++)
285    pq->q[prec].max = pq->max;
286}
287
288int
289pktq_setmax (struct pktq *pq, int max_len)
290{
291  int prec;
292
293  if (!max_len)
294    return pq->max;
295
296  pq->max = (uint16) max_len;
297  for (prec = 0; prec < pq->num_prec; prec++)
298    pq->q[prec].max = pq->max;
299
300  return pq->max;
301}
302
303void *
304pktq_deq (struct pktq *pq, int *prec_out)
305{
306  struct pktq_prec *q;
307  void *p;
308  int prec;
309
310  if (pq->len == 0)
311    return NULL;
312
313  while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
314    pq->hi_prec--;
315
316  q = &pq->q[prec];
317
318  if ((p = q->head) == NULL)
319    return NULL;
320
321  if ((q->head = PKTLINK (p)) == NULL)
322    q->tail = NULL;
323
324  q->len--;
325
326  pq->len--;
327
328  if (prec_out)
329    *prec_out = prec;
330
331  PKTSETLINK (p, NULL);
332
333  return p;
334}
335
336void *
337pktq_deq_tail (struct pktq *pq, int *prec_out)
338{
339  struct pktq_prec *q;
340  void *p, *prev;
341  int prec;
342
343  if (pq->len == 0)
344    return NULL;
345
346  for (prec = 0; prec < pq->hi_prec; prec++)
347    if (pq->q[prec].head)
348      break;
349
350  q = &pq->q[prec];
351
352  if ((p = q->head) == NULL)
353    return NULL;
354
355  for (prev = NULL; p != q->tail; p = PKTLINK (p))
356    prev = p;
357
358  if (prev)
359    PKTSETLINK (prev, NULL);
360  else
361    q->head = NULL;
362
363  q->tail = prev;
364  q->len--;
365
366  pq->len--;
367
368  if (prec_out)
369    *prec_out = prec;
370
371  PKTSETLINK (p, NULL);
372
373  return p;
374}
375
376#if 0
377void *
378pktq_peek (struct pktq *pq, int *prec_out)
379{
380  int prec;
381
382  if (pq->len == 0)
383    return NULL;
384
385  while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
386    pq->hi_prec--;
387
388  if (prec_out)
389    *prec_out = prec;
390
391  return (pq->q[prec].head);
392}
393#endif
394
395void *
396pktq_peek_tail (struct pktq *pq, int *prec_out)
397{
398  int prec;
399
400  if (pq->len == 0)
401    return NULL;
402
403  for (prec = 0; prec < pq->hi_prec; prec++)
404    if (pq->q[prec].head)
405      break;
406
407  if (prec_out)
408    *prec_out = prec;
409
410  return (pq->q[prec].tail);
411}
412
413void
414pktq_flush (osl_t * osh, struct pktq *pq, bool dir)
415{
416  int prec;
417  for (prec = 0; prec < pq->num_prec; prec++)
418    pktq_pflush (osh, pq, prec, dir);
419  ASSERT (pq->len == 0);
420}
421
422/* Return sum of lengths of a specific set of precedences */
423int
424pktq_mlen (struct pktq *pq, uint prec_bmp)
425{
426  int prec, len;
427
428  len = 0;
429
430  for (prec = 0; prec <= pq->hi_prec; prec++)
431    if (prec_bmp & (1 << prec))
432      len += pq->q[prec].len;
433
434  return len;
435}
436
437/* Priority dequeue from a specific set of precedences */
438void *
439pktq_mdeq (struct pktq *pq, uint prec_bmp, int *prec_out)
440{
441  struct pktq_prec *q;
442  void *p;
443  int prec;
444
445  if (pq->len == 0)
446    return NULL;
447
448  while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
449    pq->hi_prec--;
450
451  while ((prec_bmp & (1 << prec)) == 0 || pq->q[prec].head == NULL)
452    if (prec-- == 0)
453      return NULL;
454
455  q = &pq->q[prec];
456
457  if ((p = q->head) == NULL)
458    return NULL;
459
460  if ((q->head = PKTLINK (p)) == NULL)
461    q->tail = NULL;
462
463  q->len--;
464
465  if (prec_out)
466    *prec_out = prec;
467
468  pq->len--;
469
470  PKTSETLINK (p, NULL);
471
472  return p;
473}
474
475const unsigned char bcm_ctype[] = {
476  _BCM_C, _BCM_C, _BCM_C, _BCM_C, _BCM_C, _BCM_C, _BCM_C, _BCM_C, /* 0-7 */
477  _BCM_C, _BCM_C | _BCM_S, _BCM_C | _BCM_S, _BCM_C | _BCM_S, _BCM_C | _BCM_S,
478    _BCM_C | _BCM_S, _BCM_C,
479  _BCM_C, /* 8-15 */
480  _BCM_C, _BCM_C, _BCM_C, _BCM_C, _BCM_C, _BCM_C, _BCM_C, _BCM_C, /* 16-23 */
481  _BCM_C, _BCM_C, _BCM_C, _BCM_C, _BCM_C, _BCM_C, _BCM_C, _BCM_C, /* 24-31 */
482  _BCM_S | _BCM_SP, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, /* 32-39 */
483  _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, /* 40-47 */
484  _BCM_D, _BCM_D, _BCM_D, _BCM_D, _BCM_D, _BCM_D, _BCM_D, _BCM_D, /* 48-55 */
485  _BCM_D, _BCM_D, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, /* 56-63 */
486  _BCM_P, _BCM_U | _BCM_X, _BCM_U | _BCM_X, _BCM_U | _BCM_X, _BCM_U | _BCM_X,
487    _BCM_U | _BCM_X,
488  _BCM_U | _BCM_X, _BCM_U, /* 64-71 */
489  _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, /* 72-79 */
490  _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, /* 80-87 */
491  _BCM_U, _BCM_U, _BCM_U, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, /* 88-95 */
492  _BCM_P, _BCM_L | _BCM_X, _BCM_L | _BCM_X, _BCM_L | _BCM_X, _BCM_L | _BCM_X,
493    _BCM_L | _BCM_X,
494  _BCM_L | _BCM_X, _BCM_L, /* 96-103 */
495  _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, /* 104-111 */
496  _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, /* 112-119 */
497  _BCM_L, _BCM_L, _BCM_L, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_C, /* 120-127 */
498  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 128-143 */
499  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 144-159 */
500  _BCM_S | _BCM_SP, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P,
501    _BCM_P, _BCM_P,
502  _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, /* 160-175 */
503  _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P,
504    _BCM_P, _BCM_P,
505  _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, /* 176-191 */
506  _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U,
507    _BCM_U, _BCM_U,
508  _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, /* 192-207 */
509  _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_P, _BCM_U,
510    _BCM_U, _BCM_U,
511  _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_L, /* 208-223 */
512  _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L,
513    _BCM_L, _BCM_L,
514  _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, /* 224-239 */
515  _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_P, _BCM_L,
516    _BCM_L, _BCM_L,
517  _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L /* 240-255 */
518};
519
520ulong BCMROMFN (bcm_strtoul) (char *cp, char **endp, uint base)
521{
522  ulong result, value;
523  bool minus;
524
525  minus = FALSE;
526
527  while (bcm_isspace (*cp))
528    cp++;
529
530  if (cp[0] == '+')
531    cp++;
532  else if (cp[0] == '-')
533    {
534      minus = TRUE;
535      cp++;
536    }
537
538  if (base == 0)
539    {
540      if (cp[0] == '0')
541    {
542      if ((cp[1] == 'x') || (cp[1] == 'X'))
543        {
544          base = 16;
545          cp = &cp[2];
546        }
547      else
548        {
549          base = 8;
550          cp = &cp[1];
551        }
552    }
553      else
554    base = 10;
555    }
556  else if (base == 16 && (cp[0] == '0') && ((cp[1] == 'x') || (cp[1] == 'X')))
557    {
558      cp = &cp[2];
559    }
560
561  result = 0;
562
563  while (bcm_isxdigit (*cp) &&
564     (value =
565      bcm_isdigit (*cp) ? *cp - '0' : bcm_toupper (*cp) - 'A' + 10) <
566     base)
567    {
568      result = result * base + value;
569      cp++;
570    }
571
572  if (minus)
573    result = (ulong) (result * -1);
574
575  if (endp)
576    *endp = (char *) cp;
577
578  return (result);
579}
580
581#if 0
582int BCMROMFN (bcm_atoi) (char *s)
583{
584  return (int) bcm_strtoul (s, NULL, 10);
585}
586
587/* return pointer to location of substring 'needle' in 'haystack' */
588char *BCMROMFN (bcmstrstr) (char *haystack, char *needle)
589{
590  int len, nlen;
591  int i;
592
593  if ((haystack == NULL) || (needle == NULL))
594    return (haystack);
595
596  nlen = strlen (needle);
597  len = strlen (haystack) - nlen + 1;
598
599  for (i = 0; i < len; i++)
600    if (memcmp (needle, &haystack[i], nlen) == 0)
601      return (&haystack[i]);
602  return (NULL);
603}
604
605char *BCMROMFN (bcmstrcat) (char *dest, const char *src)
606{
607  strcpy (&dest[strlen (dest)], src);
608  return (dest);
609}
610
611char *BCMROMFN (bcmstrncat) (char *dest, const char *src, uint size)
612{
613  char *endp;
614  char *p;
615
616  p = dest + strlen (dest);
617  endp = p + size;
618
619  while (p != endp && (*p++ = *src++) != '\0')
620    ;
621
622  return (dest);
623}
624#endif
625
626/* parse a xx:xx:xx:xx:xx:xx format ethernet address */
627int BCMROMFN (bcm_ether_atoe) (char *p, struct ether_addr * ea)
628{
629  int i = 0;
630
631  for (;;)
632    {
633      ea->octet[i++] = (char) bcm_strtoul (p, &p, 16);
634      if (!*p++ || i == 6)
635    break;
636    }
637
638  return (i == 6);
639}
640
641#if defined(CONFIG_USBRNDIS_RETAIL) || defined(NDIS_MINIPORT_DRIVER)
642/* registry routine buffer preparation utility functions:
643 * parameter order is like strncpy, but returns count
644 * of bytes copied. Minimum bytes copied is null char(1)/wchar(2)
645 */
646ulong
647wchar2ascii (char *abuf, ushort * wbuf, ushort wbuflen, ulong abuflen)
648{
649  ulong copyct = 1;
650  ushort i;
651
652  if (abuflen == 0)
653    return 0;
654
655  /* wbuflen is in bytes */
656  wbuflen /= sizeof (ushort);
657
658  for (i = 0; i < wbuflen; ++i)
659    {
660      if (--abuflen == 0)
661    break;
662      *abuf++ = (char) *wbuf++;
663      ++copyct;
664    }
665  *abuf = '\0';
666
667  return copyct;
668}
669#endif /* CONFIG_USBRNDIS_RETAIL || NDIS_MINIPORT_DRIVER */
670
671#if 0
672char *
673bcm_ether_ntoa (struct ether_addr *ea, char *buf)
674{
675  snprintf (buf, 18, "%02x:%02x:%02x:%02x:%02x:%02x",
676        ea->octet[0] & 0xff, ea->octet[1] & 0xff, ea->octet[2] & 0xff,
677        ea->octet[3] & 0xff, ea->octet[4] & 0xff, ea->octet[5] & 0xff);
678  return (buf);
679}
680
681char *
682bcm_ip_ntoa (struct ipv4_addr *ia, char *buf)
683{
684  snprintf (buf, 16, "%d.%d.%d.%d",
685        ia->addr[0], ia->addr[1], ia->addr[2], ia->addr[3]);
686  return (buf);
687}
688void
689bcm_mdelay (uint ms)
690{
691  uint i;
692
693  for (i = 0; i < ms; i++)
694    {
695      OSL_DELAY (1000);
696    }
697}
698#endif
699
700#if 0
701
702/*
703 * Search the name=value vars for a specific one and return its value.
704 * Returns NULL if not found.
705 */
706char *
707getvar (char *vars, const char *name)
708{
709#ifdef _MINOSL_
710  return NULL;
711#else
712  char *s;
713  int len;
714
715  if (!name)
716    return NULL;
717
718  len = strlen (name);
719  if (len == 0)
720    return NULL;
721
722  /* first look in vars[] */
723  for (s = vars; s && *s;)
724    {
725      /* CSTYLED */
726      if ((bcmp (s, name, len) == 0) && (s[len] == '='))
727    return (&s[len + 1]);
728
729      while (*s++)
730    ;
731    }
732
733  /* then query nvram */
734  return (nvram_get (name));
735#endif /* _MINOSL_ */
736}
737
738/*
739 * Search the vars for a specific one and return its value as
740 * an integer. Returns 0 if not found.
741 */
742int
743getintvar (char *vars, const char *name)
744{
745#ifdef _MINOSL_
746  return 0;
747#else
748  char *val;
749
750  if ((val = getvar (vars, name)) == NULL)
751    return (0);
752
753  return (bcm_strtoul (val, NULL, 0));
754#endif /* _MINOSL_ */
755}
756
757
758/* Search for token in comma separated token-string */
759static int
760findmatch (char *string, char *name)
761{
762  uint len;
763  char *c;
764
765  len = strlen (name);
766  /* CSTYLED */
767  while ((c = strchr (string, ',')) != NULL)
768    {
769      if (len == (uint) (c - string) && !strncmp (string, name, len))
770    return 1;
771      string = c + 1;
772    }
773
774  return (!strcmp (string, name));
775}
776
777/* Return gpio pin number assigned to the named pin
778 *
779 * Variable should be in format:
780 *
781 * gpio<N>=pin_name,pin_name
782 *
783 * This format allows multiple features to share the gpio with mutual
784 * understanding.
785 *
786 * 'def_pin' is returned if a specific gpio is not defined for the requested functionality
787 * and if def_pin is not used by others.
788 */
789uint
790getgpiopin (char *vars, char *pin_name, uint def_pin)
791{
792  char name[] = "gpioXXXX";
793  char *val;
794  uint pin;
795
796  /* Go thru all possibilities till a match in pin name */
797  for (pin = 0; pin < GPIO_NUMPINS; pin++)
798    {
799      snprintf (name, sizeof (name), "gpio%d", pin);
800      val = getvar (vars, name);
801      if (val && findmatch (val, pin_name))
802    return pin;
803    }
804
805  if (def_pin != GPIO_PIN_NOTDEFINED)
806    {
807      /* make sure the default pin is not used by someone else */
808      snprintf (name, sizeof (name), "gpio%d", def_pin);
809      if (getvar (vars, name))
810    {
811      def_pin = GPIO_PIN_NOTDEFINED;
812    }
813    }
814
815  return def_pin;
816}
817#endif
818
819#ifdef BCMPERFSTATS
820
821#define LOGSIZE 256 /* should be power of 2 to avoid div below */
822static struct
823{
824  uint cycles;
825  char *fmt;
826  uint a1;
827  uint a2;
828} logtab[LOGSIZE];
829
830/* last entry logged */
831static uint logi = 0;
832/* next entry to read */
833static uint readi = 0;
834
835void
836bcm_perf_enable ()
837{
838  BCMPERF_ENABLE_INSTRCOUNT ();
839  BCMPERF_ENABLE_ICACHE_MISS ();
840  BCMPERF_ENABLE_ICACHE_HIT ();
841}
842
843void
844bcmlog (char *fmt, uint a1, uint a2)
845{
846  static uint last = 0;
847  uint cycles, i;
848  OSL_GETCYCLES (cycles);
849
850  i = logi;
851
852  logtab[i].cycles = cycles - last;
853  logtab[i].fmt = fmt;
854  logtab[i].a1 = a1;
855  logtab[i].a2 = a2;
856
857  logi = (i + 1) % LOGSIZE;
858  last = cycles;
859}
860
861
862void
863bcmstats (char *fmt)
864{
865  static uint last = 0;
866  static uint32 ic_miss = 0;
867  static uint32 instr_count = 0;
868  uint32 ic_miss_cur;
869  uint32 instr_count_cur;
870  uint cycles, i;
871
872  OSL_GETCYCLES (cycles);
873  BCMPERF_GETICACHE_MISS (ic_miss_cur);
874  BCMPERF_GETINSTRCOUNT (instr_count_cur);
875
876  i = logi;
877
878  logtab[i].cycles = cycles - last;
879  logtab[i].a1 = ic_miss_cur - ic_miss;
880  logtab[i].a2 = instr_count_cur - instr_count;
881  logtab[i].fmt = fmt;
882
883  logi = (i + 1) % LOGSIZE;
884
885  last = cycles;
886  instr_count = instr_count_cur;
887  ic_miss = ic_miss_cur;
888}
889
890
891void
892bcmdumplog (char *buf, int size)
893{
894  char *limit, *line;
895  int j = 0;
896  int num;
897
898  limit = buf + size - 80;
899  *buf = '\0';
900
901  num = logi - readi;
902
903  if (num < 0)
904    num += LOGSIZE;
905
906  /* print in chronological order */
907
908  for (j = 0; j < num && (buf < limit); readi = (readi + 1) % LOGSIZE, j++)
909    {
910      if (logtab[readi].fmt == NULL)
911    continue;
912      line = buf;
913      buf += sprintf (buf, "%d\t", logtab[readi].cycles);
914      buf +=
915    sprintf (buf, logtab[readi].fmt, logtab[readi].a1, logtab[readi].a2);
916      buf += sprintf (buf, "\n");
917    }
918
919}
920
921
922/*
923 * Dump one log entry at a time.
924 * Return index of next entry or -1 when no more .
925 */
926int
927bcmdumplogent (char *buf, uint i)
928{
929  bool hit;
930
931  /*
932   * If buf is NULL, return the starting index,
933   * interpreting i as the indicator of last 'i' entries to dump.
934   */
935  if (buf == NULL)
936    {
937      i = ((i > 0) && (i < (LOGSIZE - 1))) ? i : (LOGSIZE - 1);
938      return ((logi - i) % LOGSIZE);
939    }
940
941  *buf = '\0';
942
943  ASSERT (i < LOGSIZE);
944
945  if (i == logi)
946    return (-1);
947
948  hit = FALSE;
949  for (; (i != logi) && !hit; i = (i + 1) % LOGSIZE)
950    {
951      if (logtab[i].fmt == NULL)
952    continue;
953      buf += sprintf (buf, "%d: %d\t", i, logtab[i].cycles);
954      buf += sprintf (buf, logtab[i].fmt, logtab[i].a1, logtab[i].a2);
955      buf += sprintf (buf, "\n");
956      hit = TRUE;
957    }
958
959  return (i);
960}
961
962#endif /* BCMPERFSTATS */
963
964#ifdef BCMDBG
965/* pretty hex print a pkt buffer chain */
966void
967prpkt (const char *msg, osl_t * osh, void *p0)
968{
969  void *p;
970
971  if (msg && (msg[0] != '\0'))
972    printf ("%s:\n", msg);
973
974  for (p = p0; p; p = PKTNEXT (osh, p))
975    prhex (NULL, PKTDATA (osh, p), PKTLEN (osh, p));
976}
977#endif /* BCMDBG */
978
979/* Takes an Ethernet frame and sets out-of-bound PKTPRIO.
980 * Also updates the inplace vlan tag if requested.
981 * For debugging, it returns an indication of what it did.
982 */
983uint
984pktsetprio (void *pkt, bool update_vtag)
985{
986  struct ether_header *eh;
987  struct ethervlan_header *evh;
988  uint8 *pktdata;
989  int priority = 0;
990  int rc = 0;
991
992  pktdata = (uint8 *) PKTDATA (NULL, pkt);
993  ASSERT (ISALIGNED ((uintptr) pktdata, sizeof (uint16)));
994
995  eh = (struct ether_header *) pktdata;
996
997  if (ntoh16 (eh->ether_type) == ETHER_TYPE_8021Q)
998    {
999      uint16 vlan_tag;
1000      int vlan_prio, dscp_prio = 0;
1001
1002      evh = (struct ethervlan_header *) eh;
1003
1004      vlan_tag = ntoh16 (evh->vlan_tag);
1005      vlan_prio = (int) (vlan_tag >> VLAN_PRI_SHIFT) & VLAN_PRI_MASK;
1006
1007      if (ntoh16 (evh->ether_type) == ETHER_TYPE_IP)
1008    {
1009      uint8 *ip_body = pktdata + sizeof (struct ethervlan_header);
1010      uint8 tos_tc = IP_TOS (ip_body);
1011      dscp_prio = (int) (tos_tc >> IPV4_TOS_PREC_SHIFT);
1012      if ((IP_VER (ip_body) == IP_VER_4)
1013          && (IPV4_PROT (ip_body) == IP_PROT_TCP))
1014        {
1015          int ip_len;
1016          int src_port;
1017          bool src_port_exc;
1018          uint8 *tcp_hdr;
1019
1020          ip_len = IPV4_PAYLOAD_LEN (ip_body);
1021          tcp_hdr = IPV4_NO_OPTIONS_PAYLOAD (ip_body);
1022          src_port = TCP_SRC_PORT (tcp_hdr);
1023          src_port_exc = (src_port == 10110) || (src_port == 10120) ||
1024        (src_port == 10130) || (src_port == 10140);
1025
1026          if ((ip_len == 40) && src_port_exc && TCP_IS_ACK (tcp_hdr))
1027        {
1028          dscp_prio = 7;
1029        }
1030        }
1031    }
1032
1033      /* DSCP priority gets precedence over 802.1P (vlan tag) */
1034      if (dscp_prio != 0)
1035    {
1036      priority = dscp_prio;
1037      rc |= PKTPRIO_VDSCP;
1038    }
1039      else
1040    {
1041      priority = vlan_prio;
1042      rc |= PKTPRIO_VLAN;
1043    }
1044      /*
1045       * If the DSCP priority is not the same as the VLAN priority,
1046       * then overwrite the priority field in the vlan tag, with the
1047       * DSCP priority value. This is required for Linux APs because
1048       * the VLAN driver on Linux, overwrites the skb->priority field
1049       * with the priority value in the vlan tag
1050       */
1051      if (update_vtag && (priority != vlan_prio))
1052    {
1053      vlan_tag &= ~(VLAN_PRI_MASK << VLAN_PRI_SHIFT);
1054      vlan_tag |= (uint16) priority << VLAN_PRI_SHIFT;
1055      evh->vlan_tag = hton16 (vlan_tag);
1056      rc |= PKTPRIO_UPD;
1057    }
1058    }
1059  else if (ntoh16 (eh->ether_type) == ETHER_TYPE_IP)
1060    {
1061      uint8 *ip_body = pktdata + sizeof (struct ether_header);
1062      uint8 tos_tc = IP_TOS (ip_body);
1063      priority = (int) (tos_tc >> IPV4_TOS_PREC_SHIFT);
1064      rc |= PKTPRIO_DSCP;
1065      if ((IP_VER (ip_body) == IP_VER_4)
1066      && (IPV4_PROT (ip_body) == IP_PROT_TCP))
1067    {
1068      int ip_len;
1069      int src_port;
1070      bool src_port_exc;
1071      uint8 *tcp_hdr;
1072
1073      ip_len = IPV4_PAYLOAD_LEN (ip_body);
1074      tcp_hdr = IPV4_NO_OPTIONS_PAYLOAD (ip_body);
1075      src_port = TCP_SRC_PORT (tcp_hdr);
1076      src_port_exc = (src_port == 10110) || (src_port == 10120) ||
1077        (src_port == 10130) || (src_port == 10140);
1078
1079      if ((ip_len == 40) && src_port_exc && TCP_IS_ACK (tcp_hdr))
1080        {
1081          priority = 7;
1082        }
1083    }
1084    }
1085
1086  ASSERT (priority >= 0 && priority <= MAXPRIO);
1087  PKTSETPRIO (pkt, priority);
1088  return (rc | priority);
1089}
1090
1091static char bcm_undeferrstr[BCME_STRLEN];
1092
1093static const char *bcmerrorstrtable[] = BCMERRSTRINGTABLE;
1094
1095/* Convert the error codes into related error strings */
1096const char *
1097bcmerrorstr (int bcmerror)
1098{
1099  /* check if someone added a bcmerror code but forgot to add errorstring */
1100  ASSERT (ABS (BCME_LAST) == (ARRAYSIZE (bcmerrorstrtable) - 1));
1101
1102  if (bcmerror > 0 || bcmerror < BCME_LAST)
1103    {
1104      snprintf (bcm_undeferrstr, BCME_STRLEN, "Undefined error %d", bcmerror);
1105      return bcm_undeferrstr;
1106    }
1107
1108  ASSERT (strlen (bcmerrorstrtable[-bcmerror]) < BCME_STRLEN);
1109
1110  return bcmerrorstrtable[-bcmerror];
1111}
1112
1113#if 0
1114static void BCMINITFN (bcm_nvram_refresh) (char *flash)
1115{
1116  int i;
1117  int ret = 0;
1118
1119  ASSERT (flash);
1120
1121  /* default "empty" vars cache */
1122  bzero (flash, 2);
1123
1124  if ((ret = nvram_getall (flash, NVRAM_SPACE)))
1125    return;
1126
1127  /* determine nvram length */
1128  for (i = 0; i < NVRAM_SPACE; i++)
1129    {
1130      if (flash[i] == '\0' && flash[i + 1] == '\0')
1131    break;
1132    }
1133
1134  if (i > 1)
1135    vars_len = i + 2;
1136  else
1137    vars_len = 0;
1138}
1139#endif
1140
1141#ifdef BCMDBG_PKT /* pkt logging for debugging */
1142/* Add a packet to the pktlist */
1143void
1144pktlist_add (pktlist_info_t * pktlist, void *pkt)
1145{
1146  uint i;
1147  ASSERT (pktlist->count < PKTLIST_SIZE);
1148
1149  /* Verify the packet is not already part of the list */
1150  for (i = 0; i < pktlist->count; i++)
1151    {
1152      if (pktlist->list[i] == pkt)
1153    ASSERT (0);
1154    }
1155  pktlist->list[pktlist->count] = pkt;
1156  pktlist->count++;
1157  return;
1158}
1159
1160/* Remove a packet from the pktlist */
1161void
1162pktlist_remove (pktlist_info_t * pktlist, void *pkt)
1163{
1164  uint i;
1165  uint num = pktlist->count;
1166
1167  /* find the index where pkt exists */
1168  for (i = 0; i < num; i++)
1169    {
1170      /* check for the existence of pkt in the list */
1171      if (pktlist->list[i] == pkt)
1172    {
1173      /* replace with the last element */
1174      pktlist->list[i] = pktlist->list[num - 1];
1175      pktlist->count--;
1176      return;
1177    }
1178    }
1179  ASSERT (0);
1180}
1181
1182/* Dump the pktlist (and the contents of each packet if 'data'
1183 * is set). 'buf' should be large enough
1184 */
1185
1186char *
1187pktlist_dump (pktlist_info_t * pktlist, char *buf)
1188{
1189  char *obuf;
1190  uint i;
1191
1192  obuf = buf;
1193
1194  buf += sprintf (buf, "Packet list dump:\n");
1195
1196  for (i = 0; i < (pktlist->count); i++)
1197    {
1198      buf += sprintf (buf, "0x%p\t", pktlist->list[i]);
1199
1200#ifdef NOTDEF /* Remove this ifdef to print pkttag and pktdata */
1201      if (PKTTAG (pktlist->list[i]))
1202    {
1203      /* Print pkttag */
1204      buf += sprintf (buf, "Pkttag(in hex): ");
1205      buf +=
1206        bcm_format_hex (buf, PKTTAG (pktlist->list[i]), OSL_PKTTAG_SZ);
1207    }
1208      buf += sprintf (buf, "Pktdata(in hex): ");
1209      buf += bcm_format_hex (buf, PKTDATA (NULL, pktlist->list[i]),
1210                 PKTLEN (NULL, pktlist->list[i]));
1211#endif /* NOTDEF */
1212
1213      buf += sprintf (buf, "\n");
1214    }
1215  return obuf;
1216}
1217#endif /* BCMDBG_PKT */
1218
1219#if 0
1220/* iovar table lookup */
1221const bcm_iovar_t *
1222bcm_iovar_lookup (const bcm_iovar_t * table, const char *name)
1223{
1224  const bcm_iovar_t *vi;
1225  const char *lookup_name;
1226
1227  /* skip any ':' delimited option prefixes */
1228  lookup_name = strrchr (name, ':');
1229  if (lookup_name != NULL)
1230    lookup_name++;
1231  else
1232    lookup_name = name;
1233
1234  ASSERT (table);
1235
1236  for (vi = table; vi->name; vi++)
1237    {
1238      if (!strcmp (vi->name, lookup_name))
1239    return vi;
1240    }
1241  /* ran to end of table */
1242
1243  return NULL; /* var name not found */
1244}
1245#endif
1246
1247int
1248bcm_iovar_lencheck (const bcm_iovar_t * vi, void *arg, int len, bool set)
1249{
1250  int bcmerror = 0;
1251
1252  /* length check on io buf */
1253  switch (vi->type)
1254    {
1255    case IOVT_BOOL:
1256    case IOVT_INT8:
1257    case IOVT_INT16:
1258    case IOVT_INT32:
1259    case IOVT_UINT8:
1260    case IOVT_UINT16:
1261    case IOVT_UINT32:
1262      /* all integers are int32 sized args at the ioctl interface */
1263      if (len < (int) sizeof (int))
1264    {
1265      bcmerror = BCME_BUFTOOSHORT;
1266    }
1267      break;
1268
1269    case IOVT_BUFFER:
1270      /* buffer must meet minimum length requirement */
1271      if (len < vi->minlen)
1272    {
1273      bcmerror = BCME_BUFTOOSHORT;
1274    }
1275      break;
1276
1277    case IOVT_VOID:
1278      if (!set)
1279    {
1280      /* Cannot return nil... */
1281      bcmerror = BCME_UNSUPPORTED;
1282    }
1283      else if (len)
1284    {
1285      /* Set is an action w/o parameters */
1286      bcmerror = BCME_BUFTOOLONG;
1287    }
1288      break;
1289
1290    default:
1291      /* unknown type for length check in iovar info */
1292      ASSERT (0);
1293      bcmerror = BCME_UNSUPPORTED;
1294    }
1295
1296  return bcmerror;
1297}
1298
1299#define CRC_INNER_LOOP(n, c, x) \
1300    (c) = ((c) >> 8) ^ crc##n##_table[((c) ^ (x)) & 0xff]
1301
1302#if 0
1303/*******************************************************************************
1304 * crc8
1305 *
1306 * Computes a crc8 over the input data using the polynomial:
1307 *
1308 * x^8 + x^7 +x^6 + x^4 + x^2 + 1
1309 *
1310 * The caller provides the initial value (either CRC8_INIT_VALUE
1311 * or the previous returned value) to allow for processing of
1312 * discontiguous blocks of data. When generating the CRC the
1313 * caller is responsible for complementing the final return value
1314 * and inserting it into the byte stream. When checking, a final
1315 * return value of CRC8_GOOD_VALUE indicates a valid CRC.
1316 *
1317 * Reference: Dallas Semiconductor Application Note 27
1318 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
1319 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
1320 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
1321 *
1322 * ****************************************************************************
1323 */
1324
1325static const uint8 crc8_table[256] = {
1326  0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
1327  0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
1328  0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
1329  0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
1330  0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
1331  0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
1332  0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
1333  0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
1334  0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
1335  0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
1336  0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
1337  0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
1338  0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
1339  0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
1340  0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
1341  0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
1342  0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
1343  0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
1344  0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
1345  0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
1346  0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
1347  0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
1348  0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
1349  0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
1350  0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
1351  0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
1352  0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
1353  0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
1354  0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
1355  0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
1356  0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
1357  0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F
1358};
1359
1360uint8 BCMROMFN (hndcrc8) (uint8 * pdata, /* pointer to array of data to process */
1361              uint nbytes, /* number of input data bytes to process */
1362              uint8 crc /* either CRC8_INIT_VALUE or previous return value */
1363  )
1364{
1365  /* hard code the crc loop instead of using CRC_INNER_LOOP macro
1366   * to avoid the undefined and unnecessary (uint8 >> 8) operation.
1367   */
1368  while (nbytes-- > 0)
1369    crc = crc8_table[(crc ^ *pdata++) & 0xff];
1370
1371  return crc;
1372}
1373
1374/*******************************************************************************
1375 * crc16
1376 *
1377 * Computes a crc16 over the input data using the polynomial:
1378 *
1379 * x^16 + x^12 +x^5 + 1
1380 *
1381 * The caller provides the initial value (either CRC16_INIT_VALUE
1382 * or the previous returned value) to allow for processing of
1383 * discontiguous blocks of data. When generating the CRC the
1384 * caller is responsible for complementing the final return value
1385 * and inserting it into the byte stream. When checking, a final
1386 * return value of CRC16_GOOD_VALUE indicates a valid CRC.
1387 *
1388 * Reference: Dallas Semiconductor Application Note 27
1389 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
1390 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
1391 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
1392 *
1393 * ****************************************************************************
1394 */
1395static const uint16 crc16_table[256] = {
1396  0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF,
1397  0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7,
1398  0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E,
1399  0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876,
1400  0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD,
1401  0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5,
1402  0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C,
1403  0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974,
1404  0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB,
1405  0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3,
1406  0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A,
1407  0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72,
1408  0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9,
1409  0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1,
1410  0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738,
1411  0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70,
1412  0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7,
1413  0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF,
1414  0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036,
1415  0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E,
1416  0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5,
1417  0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD,
1418  0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134,
1419  0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C,
1420  0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3,
1421  0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB,
1422  0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232,
1423  0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A,
1424  0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1,
1425  0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9,
1426  0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330,
1427  0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78
1428};
1429
1430uint16 BCMROMFN (hndcrc16) (uint8 * pdata, /* pointer to array of data to process */
1431                uint nbytes, /* number of input data bytes to process */
1432                uint16 crc /* either CRC16_INIT_VALUE or previous return value */
1433  )
1434{
1435  while (nbytes-- > 0)
1436    CRC_INNER_LOOP (16, crc, *pdata++);
1437  return crc;
1438}
1439#endif
1440
1441static const uint32 crc32_table[256] = {
1442  0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
1443  0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
1444  0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
1445  0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
1446  0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
1447  0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
1448  0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
1449  0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
1450  0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
1451  0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
1452  0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
1453  0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
1454  0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
1455  0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
1456  0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
1457  0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
1458  0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
1459  0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
1460  0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
1461  0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
1462  0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
1463  0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
1464  0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
1465  0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
1466  0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
1467  0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
1468  0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
1469  0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
1470  0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
1471  0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
1472  0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
1473  0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
1474  0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
1475  0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
1476  0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
1477  0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
1478  0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
1479  0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
1480  0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
1481  0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
1482  0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
1483  0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
1484  0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
1485  0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
1486  0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
1487  0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
1488  0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
1489  0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
1490  0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
1491  0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
1492  0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
1493  0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
1494  0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
1495  0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
1496  0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
1497  0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
1498  0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
1499  0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
1500  0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
1501  0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
1502  0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
1503  0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
1504  0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
1505  0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
1506};
1507
1508uint32 BCMROMFN (hndcrc32) (uint8 * pdata, /* pointer to array of data to process */
1509                uint nbytes, /* number of input data bytes to process */
1510                uint32 crc /* either CRC32_INIT_VALUE or previous return value */
1511  )
1512{
1513  uint8 *pend;
1514#ifdef __mips__
1515  uint8 tmp[4];
1516  ulong *tptr = (ulong *) tmp;
1517
1518  /* in case the beginning of the buffer isn't aligned */
1519  pend = (uint8 *) ((uint) (pdata + 3) & 0xfffffffc);
1520  nbytes -= (pend - pdata);
1521  while (pdata < pend)
1522    CRC_INNER_LOOP (32, crc, *pdata++);
1523
1524  /* handle bulk of data as 32-bit words */
1525  pend = pdata + (nbytes & 0xfffffffc);
1526  while (pdata < pend)
1527    {
1528      *tptr = *(ulong *) pdata;
1529      pdata += sizeof (ulong *);
1530      CRC_INNER_LOOP (32, crc, tmp[0]);
1531      CRC_INNER_LOOP (32, crc, tmp[1]);
1532      CRC_INNER_LOOP (32, crc, tmp[2]);
1533      CRC_INNER_LOOP (32, crc, tmp[3]);
1534    }
1535
1536  /* 1-3 bytes at end of buffer */
1537  pend = pdata + (nbytes & 0x03);
1538  while (pdata < pend)
1539    CRC_INNER_LOOP (32, crc, *pdata++);
1540#else
1541  pend = pdata + nbytes;
1542  while (pdata < pend)
1543    CRC_INNER_LOOP (32, crc, *pdata++);
1544#endif /* __mips__ */
1545
1546  return crc;
1547}
1548
1549#ifdef notdef
1550#define CLEN 1499 /* CRC Length */
1551#define CBUFSIZ (CLEN+4)
1552#define CNBUFS 5 /* # of bufs */
1553
1554void
1555testcrc32 (void)
1556{
1557  uint j, k, l;
1558  uint8 *buf;
1559  uint len[CNBUFS];
1560  uint32 crcr;
1561  uint32 crc32tv[CNBUFS] =
1562    { 0xd2cb1faa, 0xd385c8fa, 0xf5b4f3f3, 0x55789e20, 0x00343110 };
1563
1564  ASSERT ((buf = MALLOC (CBUFSIZ * CNBUFS)) != NULL);
1565
1566  /* step through all possible alignments */
1567  for (l = 0; l <= 4; l++)
1568    {
1569      for (j = 0; j < CNBUFS; j++)
1570    {
1571      len[j] = CLEN;
1572      for (k = 0; k < len[j]; k++)
1573        *(buf + j * CBUFSIZ + (k + l)) = (j + k) & 0xff;
1574    }
1575
1576      for (j = 0; j < CNBUFS; j++)
1577    {
1578      crcr = crc32 (buf + j * CBUFSIZ + l, len[j], CRC32_INIT_VALUE);
1579      ASSERT (crcr == crc32tv[j]);
1580    }
1581    }
1582
1583  MFREE (buf, CBUFSIZ * CNBUFS);
1584  return;
1585}
1586#endif /* notdef */
1587
1588/*
1589 * Advance from the current 1-byte tag/1-byte length/variable-length value
1590 * triple, to the next, returning a pointer to the next.
1591 * If the current or next TLV is invalid (does not fit in given buffer length),
1592 * NULL is returned.
1593 * *buflen is not modified if the TLV elt parameter is invalid, or is decremented
1594 * by the TLV parameter's length if it is valid.
1595 */
1596bcm_tlv_t *BCMROMFN (bcm_next_tlv) (bcm_tlv_t * elt, int *buflen)
1597{
1598  int len;
1599
1600  /* validate current elt */
1601  if (!bcm_valid_tlv (elt, *buflen))
1602    return NULL;
1603
1604  /* advance to next elt */
1605  len = elt->len;
1606  elt = (bcm_tlv_t *) (elt->data + len);
1607  *buflen -= (2 + len);
1608
1609  /* validate next elt */
1610  if (!bcm_valid_tlv (elt, *buflen))
1611    return NULL;
1612
1613  return elt;
1614}
1615
1616/*
1617 * Traverse a string of 1-byte tag/1-byte length/variable-length value
1618 * triples, returning a pointer to the substring whose first element
1619 * matches tag
1620 */
1621bcm_tlv_t *BCMROMFN (bcm_parse_tlvs) (void *buf, int buflen, uint key)
1622{
1623  bcm_tlv_t *elt;
1624  int totlen;
1625
1626  elt = (bcm_tlv_t *) buf;
1627  totlen = buflen;
1628
1629  /* find tagged parameter */
1630  while (totlen >= 2)
1631    {
1632      int len = elt->len;
1633
1634      /* validate remaining totlen */
1635      if ((elt->id == key) && (totlen >= (len + 2)))
1636    return (elt);
1637
1638      elt = (bcm_tlv_t *) ((uint8 *) elt + (len + 2));
1639      totlen -= (len + 2);
1640    }
1641
1642  return NULL;
1643}
1644
1645#if 0
1646/*
1647 * Traverse a string of 1-byte tag/1-byte length/variable-length value
1648 * triples, returning a pointer to the substring whose first element
1649 * matches tag. Stop parsing when we see an element whose ID is greater
1650 * than the target key.
1651 */
1652bcm_tlv_t *BCMROMFN (bcm_parse_ordered_tlvs) (void *buf, int buflen, uint key)
1653{
1654  bcm_tlv_t *elt;
1655  int totlen;
1656
1657  elt = (bcm_tlv_t *) buf;
1658  totlen = buflen;
1659
1660  /* find tagged parameter */
1661  while (totlen >= 2)
1662    {
1663      uint id = elt->id;
1664      int len = elt->len;
1665
1666      /* Punt if we start seeing IDs > than target key */
1667      if (id > key)
1668    return (NULL);
1669
1670      /* validate remaining totlen */
1671      if ((id == key) && (totlen >= (len + 2)))
1672    return (elt);
1673
1674      elt = (bcm_tlv_t *) ((uint8 *) elt + (len + 2));
1675      totlen -= (len + 2);
1676    }
1677  return NULL;
1678}
1679
1680#ifdef BCMDBG
1681int
1682bcm_format_flags (const bcm_bit_desc_t * bd, uint32 flags, char *buf, int len)
1683{
1684  int i;
1685  char *p = buf;
1686  char hexstr[16];
1687  int slen = 0;
1688  uint32 bit;
1689  const char *name;
1690
1691  if (len < 2 || !buf)
1692    return 0;
1693
1694  buf[0] = '\0';
1695  len -= 1;
1696
1697  for (i = 0; flags != 0; i++)
1698    {
1699      bit = bd[i].bit;
1700      name = bd[i].name;
1701      if (bit == 0 && flags)
1702    {
1703      /* print any unnamed bits */
1704      sprintf (hexstr, "0x%X", flags);
1705      name = hexstr;
1706      flags = 0; /* exit loop */
1707    }
1708      else if ((flags & bit) == 0)
1709    continue;
1710      slen += strlen (name);
1711      if (len < slen)
1712    break;
1713      if (p != buf)
1714    p += sprintf (p, " "); /* btwn flag space */
1715      strcat (p, name);
1716      p += strlen (name);
1717      flags &= ~bit;
1718      len -= slen;
1719      slen = 1; /* account for btwn flag space */
1720    }
1721
1722  /* indicate the str was too short */
1723  if (flags != 0)
1724    {
1725      if (len == 0)
1726    p--; /* overwrite last char */
1727      p += sprintf (p, ">");
1728    }
1729
1730  return (int) (p - buf);
1731}
1732
1733void
1734deadbeef (void *p, uint len)
1735{
1736  static uint8 meat[] = { 0xde, 0xad, 0xbe, 0xef };
1737
1738  while (len-- > 0)
1739    {
1740      *(uint8 *) p = meat[((uintptr) p) & 3];
1741      p = (uint8 *) p + 1;
1742    }
1743}
1744
1745/* pretty hex print a contiguous buffer */
1746void
1747prhex (const char *msg, uchar * buf, uint nbytes)
1748{
1749  char line[128], *p;
1750  uint i;
1751
1752  if (msg && (msg[0] != '\0'))
1753    printf ("%s:\n", msg);
1754
1755  p = line;
1756  for (i = 0; i < nbytes; i++)
1757    {
1758      if (i % 16 == 0)
1759    {
1760      p += sprintf (p, " %04d: ", i); /* line prefix */
1761    }
1762      p += sprintf (p, "%02x ", buf[i]);
1763      if (i % 16 == 15)
1764    {
1765      printf ("%s\n", line); /* flush line */
1766      p = line;
1767    }
1768    }
1769
1770  /* flush last partial line */
1771  if (p != line)
1772    printf ("%s\n", line);
1773}
1774
1775/* print bytes formatted as hex to a string. return the resulting string length */
1776int
1777bcm_format_hex (char *str, const void *bytes, int len)
1778{
1779  int i;
1780  char *p = str;
1781  const uint8 *src = (const uint8 *) bytes;
1782
1783  for (i = 0; i < len; i++)
1784    {
1785      p += sprintf (p, "%02X", *src);
1786      src++;
1787    }
1788  return (int) (p - str);
1789}
1790
1791#endif /* BCMDBG */
1792
1793/* Produce a human-readable string for boardrev */
1794char *
1795bcm_brev_str (uint16 brev, char *buf)
1796{
1797  if (brev < 0x100)
1798    snprintf (buf, 8, "%d.%d", (brev & 0xf0) >> 4, brev & 0xf);
1799  else
1800    snprintf (buf, 8, "%c%03x", ((brev & 0xf000) == 0x1000) ? 'P' : 'A',
1801          brev & 0xfff);
1802
1803  return (buf);
1804}
1805
1806#define BUFSIZE_TODUMP_ATONCE 512 /* Buffer size */
1807
1808/* dump large strings to console */
1809void
1810printfbig (char *buf)
1811{
1812  uint len, max_len;
1813  char c;
1814
1815  len = strlen (buf);
1816
1817  max_len = BUFSIZE_TODUMP_ATONCE;
1818
1819  while (len > max_len)
1820    {
1821      c = buf[max_len];
1822      buf[max_len] = '\0';
1823      printf ("%s", buf);
1824      buf[max_len] = c;
1825
1826      buf += max_len;
1827      len -= max_len;
1828    }
1829  /* print the remaining string */
1830  printf ("%s\n", buf);
1831  return;
1832}
1833
1834/* routine to dump fields in a fileddesc structure */
1835uint
1836bcmdumpfields (readreg_rtn read_rtn, void *arg0, void *arg1,
1837           struct fielddesc * fielddesc_array, char *buf, uint32 bufsize)
1838{
1839  uint filled_len;
1840  int len;
1841  struct fielddesc *cur_ptr;
1842
1843  filled_len = 0;
1844  cur_ptr = fielddesc_array;
1845
1846  while (bufsize > 1)
1847    {
1848      if (cur_ptr->nameandfmt == NULL)
1849    break;
1850      len = snprintf (buf, bufsize, cur_ptr->nameandfmt,
1851              read_rtn (arg0, arg1, cur_ptr->offset));
1852      /* check for snprintf overflow or error */
1853      if (len < 0 || (uint32) len >= bufsize)
1854    len = bufsize - 1;
1855      buf += len;
1856      bufsize -= len;
1857      filled_len += len;
1858      cur_ptr++;
1859    }
1860  return filled_len;
1861}
1862#endif
1863
1864uint
1865bcm_mkiovar (char *name, char *data, uint datalen, char *buf, uint buflen)
1866{
1867  uint len;
1868
1869  len = strlen (name) + 1;
1870
1871  if ((len + datalen) > buflen)
1872    return 0;
1873
1874  strncpy (buf, name, buflen);
1875
1876  /* append data onto the end of the name string */
1877  memcpy (&buf[len], data, datalen);
1878  len += datalen;
1879
1880  return len;
1881}
1882
1883/* Quarter dBm units to mW
1884 * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153
1885 * Table is offset so the last entry is largest mW value that fits in
1886 * a uint16.
1887 */
1888
1889#define QDBM_OFFSET 153 /* Offset for first entry */
1890#define QDBM_TABLE_LEN 40 /* Table size */
1891
1892/* Smallest mW value that will round up to the first table entry, QDBM_OFFSET.
1893 * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2
1894 */
1895#define QDBM_TABLE_LOW_BOUND 6493 /* Low bound */
1896
1897/* Largest mW value that will round down to the last table entry,
1898 * QDBM_OFFSET + QDBM_TABLE_LEN-1.
1899 * Value is ( mW(QDBM_OFFSET + QDBM_TABLE_LEN - 1) + mW(QDBM_OFFSET + QDBM_TABLE_LEN) ) / 2.
1900 */
1901#define QDBM_TABLE_HIGH_BOUND 64938 /* High bound */
1902
1903static const uint16 nqdBm_to_mW_map[QDBM_TABLE_LEN] = {
1904/* qdBm: +0 +1 +2 +3 +4 +5 +6 +7 */
1905/* 153: */ 6683, 7079, 7499, 7943, 8414, 8913, 9441, 10000,
1906/* 161: */ 10593, 11220, 11885, 12589, 13335, 14125, 14962, 15849,
1907/* 169: */ 16788, 17783, 18836, 19953, 21135, 22387, 23714, 25119,
1908/* 177: */ 26607, 28184, 29854, 31623, 33497, 35481, 37584, 39811,
1909/* 185: */ 42170, 44668, 47315, 50119, 53088, 56234, 59566, 63096
1910};
1911
1912uint16 BCMROMFN (bcm_qdbm_to_mw) (uint8 qdbm)
1913{
1914  uint factor = 1;
1915  int idx = qdbm - QDBM_OFFSET;
1916
1917  if (idx > QDBM_TABLE_LEN)
1918    {
1919      /* clamp to max uint16 mW value */
1920      return 0xFFFF;
1921    }
1922
1923  /* scale the qdBm index up to the range of the table 0-40
1924   * where an offset of 40 qdBm equals a factor of 10 mW.
1925   */
1926  while (idx < 0)
1927    {
1928      idx += 40;
1929      factor *= 10;
1930    }
1931
1932  /* return the mW value scaled down to the correct factor of 10,
1933   * adding in factor/2 to get proper rounding.
1934   */
1935  return ((nqdBm_to_mW_map[idx] + factor / 2) / factor);
1936}
1937
1938uint8 BCMROMFN (bcm_mw_to_qdbm) (uint16 mw)
1939{
1940  uint8 qdbm;
1941  int offset;
1942  uint mw_uint = mw;
1943  uint boundary;
1944
1945  /* handle boundary case */
1946  if (mw_uint <= 1)
1947    return 0;
1948
1949  offset = QDBM_OFFSET;
1950
1951  /* move mw into the range of the table */
1952  while (mw_uint < QDBM_TABLE_LOW_BOUND)
1953    {
1954      mw_uint *= 10;
1955      offset -= 40;
1956    }
1957
1958  for (qdbm = 0; qdbm < QDBM_TABLE_LEN - 1; qdbm++)
1959    {
1960      boundary = nqdBm_to_mW_map[qdbm] + (nqdBm_to_mW_map[qdbm + 1] -
1961                      nqdBm_to_mW_map[qdbm]) / 2;
1962      if (mw_uint < boundary)
1963    break;
1964    }
1965
1966  qdbm += (uint8) offset;
1967
1968  return (qdbm);
1969}
1970
1971
1972uint BCMROMFN (bcm_bitcount) (uint8 * bitmap, uint length)
1973{
1974  uint bitcount = 0, i;
1975  uint8 tmp;
1976  for (i = 0; i < length; i++)
1977    {
1978      tmp = bitmap[i];
1979      while (tmp)
1980    {
1981      bitcount++;
1982      tmp &= (tmp - 1);
1983    }
1984    }
1985  return bitcount;
1986}
1987
1988
1989/* Initialization of bcmstrbuf structure */
1990void
1991bcm_binit (struct bcmstrbuf *b, char *buf, uint size)
1992{
1993  b->origsize = b->size = size;
1994  b->origbuf = b->buf = buf;
1995}
1996
1997/* Buffer sprintf wrapper to guard against buffer overflow */
1998int
1999bcm_bprintf (struct bcmstrbuf *b, const char *fmt, ...)
2000{
2001  va_list ap;
2002  int r;
2003
2004  va_start (ap, fmt);
2005  r = vsnprintf (b->buf, b->size, fmt, ap);
2006
2007  /* Non Ansi C99 compliant returns -1,
2008   * Ansi compliant return r >= b->size,
2009   * bcmstdlib returns 0, handle all
2010   */
2011  if ((r == -1) || (r >= (int) b->size) || (r == 0))
2012    {
2013      b->size = 0;
2014    }
2015  else
2016    {
2017      b->size -= r;
2018      b->buf += r;
2019    }
2020
2021  va_end (ap);
2022
2023  return r;
2024}
2025
2026char *
2027bcm_ether_ntoa (struct ether_addr *ea, char *buf)
2028{
2029    snprintf (buf, 18, "%02x:%02x:%02x:%02x:%02x:%02x",
2030        ea->octet[0] & 0xff, ea->octet[1] & 0xff, ea->octet[2] & 0xff,
2031        ea->octet[3] & 0xff, ea->octet[4] & 0xff, ea->octet[5] & 0xff);
2032    return (buf);
2033}
2034
package/broadcom-wl-old/src/driver/bcmutils.h
1/*
2 * Misc useful os-independent macros and functions.
3 *
4 * Copyright 2007, Broadcom Corporation
5 * All Rights Reserved.
6 *
7 * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
8 * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
9 * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
10 * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
11 */
12
13#ifndef _bcmutils_h_
14#define _bcmutils_h_
15#include "linux_osl.h"
16
17/* ctype replacement */
18#define _BCM_U 0x01 /* upper */
19#define _BCM_L 0x02 /* lower */
20#define _BCM_D 0x04 /* digit */
21#define _BCM_C 0x08 /* cntrl */
22#define _BCM_P 0x10 /* punct */
23#define _BCM_S 0x20 /* white space (space/lf/tab) */
24#define _BCM_X 0x40 /* hex digit */
25#define _BCM_SP 0x80 /* hard space (0x20) */
26
27extern const unsigned char bcm_ctype[];
28#define bcm_ismask(x) (bcm_ctype[(int)(unsigned char)(x)])
29
30#define bcm_isalnum(c) ((bcm_ismask(c)&(_BCM_U|_BCM_L|_BCM_D)) != 0)
31#define bcm_isalpha(c) ((bcm_ismask(c)&(_BCM_U|_BCM_L)) != 0)
32#define bcm_iscntrl(c) ((bcm_ismask(c)&(_BCM_C)) != 0)
33#define bcm_isdigit(c) ((bcm_ismask(c)&(_BCM_D)) != 0)
34#define bcm_isgraph(c) ((bcm_ismask(c)&(_BCM_P|_BCM_U|_BCM_L|_BCM_D)) != 0)
35#define bcm_islower(c) ((bcm_ismask(c)&(_BCM_L)) != 0)
36#define bcm_isprint(c) ((bcm_ismask(c)&(_BCM_P|_BCM_U|_BCM_L|_BCM_D|_BCM_SP)) != 0)
37#define bcm_ispunct(c) ((bcm_ismask(c)&(_BCM_P)) != 0)
38#define bcm_isspace(c) ((bcm_ismask(c)&(_BCM_S)) != 0)
39#define bcm_isupper(c) ((bcm_ismask(c)&(_BCM_U)) != 0)
40#define bcm_isxdigit(c) ((bcm_ismask(c)&(_BCM_D|_BCM_X)) != 0)
41#define bcm_tolower(c) (bcm_isupper((c)) ? ((c) + 'a' - 'A') : (c))
42#define bcm_toupper(c) (bcm_islower((c)) ? ((c) + 'A' - 'a') : (c))
43
44/* Buffer structure for collecting string-formatted data
45* using bcm_bprintf() API.
46* Use bcm_binit() to initialize before use
47*/
48
49struct bcmstrbuf {
50    char *buf; /* pointer to current position in origbuf */
51    unsigned int size; /* current (residual) size in bytes */
52    char *origbuf; /* unmodified pointer to orignal buffer */
53    unsigned int origsize; /* unmodified orignal buffer size in bytes */
54};
55
56/* ** driver-only section ** */
57#include <osl.h>
58
59#define GPIO_PIN_NOTDEFINED 0x20 /* Pin not defined */
60
61
62/* osl multi-precedence packet queue */
63#ifndef PKTQ_LEN_DEFAULT
64#define PKTQ_LEN_DEFAULT 128 /* Max 128 packets */
65#endif
66#ifndef PKTQ_MAX_PREC
67#define PKTQ_MAX_PREC 16 /* Maximum precedence levels */
68#endif
69
70typedef struct pktq_prec {
71    void *head; /* first packet to dequeue */
72    void *tail; /* last packet to dequeue */
73    uint16 len; /* number of queued packets */
74    uint16 max; /* maximum number of queued packets */
75} pktq_prec_t;
76
77
78/* multi-priority pkt queue */
79struct pktq {
80    uint16 num_prec; /* number of precedences in use */
81    uint16 hi_prec; /* rapid dequeue hint (>= highest non-empty prec) */
82    uint16 max; /* total max packets */
83    uint16 len; /* total number of packets */
84    /* q array must be last since # of elements can be either PKTQ_MAX_PREC or 1 */
85    struct pktq_prec q[PKTQ_MAX_PREC];
86};
87
88/* simple, non-priority pkt queue */
89struct spktq {
90    uint16 num_prec; /* number of precedences in use (always 1) */
91    uint16 hi_prec; /* rapid dequeue hint (>= highest non-empty prec) */
92    uint16 max; /* total max packets */
93    uint16 len; /* total number of packets */
94    /* q array must be last since # of elements can be either PKTQ_MAX_PREC or 1 */
95    struct pktq_prec q[1];
96};
97
98#define PKTQ_PREC_ITER(pq, prec) for (prec = (pq)->num_prec - 1; prec >= 0; prec--)
99
100/* forward definition of ether_addr structure used by some function prototypes */
101struct ether_addr;
102
103/* operations on a specific precedence in packet queue */
104
105#define pktq_psetmax(pq, prec, _max) ((pq)->q[prec].max = (_max))
106#define pktq_plen(pq, prec) ((pq)->q[prec].len)
107#define pktq_pavail(pq, prec) ((pq)->q[prec].max - (pq)->q[prec].len)
108#define pktq_pfull(pq, prec) ((pq)->q[prec].len >= (pq)->q[prec].max)
109#define pktq_pempty(pq, prec) ((pq)->q[prec].len == 0)
110
111#define pktq_ppeek(pq, prec) ((pq)->q[prec].head)
112#define pktq_ppeek_tail(pq, prec) ((pq)->q[prec].tail)
113
114extern void *pktq_penq(struct pktq *pq, int prec, void *p);
115extern void *pktq_penq_head(struct pktq *pq, int prec, void *p);
116extern void *pktq_pdeq(struct pktq *pq, int prec);
117extern void *pktq_pdeq_tail(struct pktq *pq, int prec);
118/* Empty the queue at particular precedence level */
119extern void pktq_pflush(osl_t *osh, struct pktq *pq, int prec, bool dir);
120/* Remove a specified packet from its queue */
121extern bool pktq_pdel(struct pktq *pq, void *p, int prec);
122
123/* operations on a set of precedences in packet queue */
124
125extern int pktq_mlen(struct pktq *pq, uint prec_bmp);
126extern void *pktq_mdeq(struct pktq *pq, uint prec_bmp, int *prec_out);
127
128/* operations on packet queue as a whole */
129
130#define pktq_len(pq) ((int)(pq)->len)
131#define pktq_max(pq) ((int)(pq)->max)
132#define pktq_avail(pq) ((int)((pq)->max - (pq)->len))
133#define pktq_full(pq) ((pq)->len >= (pq)->max)
134#define pktq_empty(pq) ((pq)->len == 0)
135
136/* operations for single precedence queues */
137#define pktenq(pq, p) pktq_penq(((struct pktq *)pq), 0, (p))
138#define pktenq_head(pq, p) pktq_penq_head(((struct pktq *)pq), 0, (p))
139#define pktdeq(pq) pktq_pdeq(((struct pktq *)pq), 0)
140#define pktdeq_tail(pq) pktq_pdeq_tail(((struct pktq *)pq), 0)
141#define pktqinit(pq, len) pktq_init(((struct pktq *)pq), 1, len)
142
143extern void pktq_init(struct pktq *pq, int num_prec, int max_len);
144/* prec_out may be NULL if caller is not interested in return value */
145extern void *pktq_deq(struct pktq *pq, int *prec_out);
146extern void *pktq_deq_tail(struct pktq *pq, int *prec_out);
147extern void *pktq_peek(struct pktq *pq, int *prec_out);
148extern void *pktq_peek_tail(struct pktq *pq, int *prec_out);
149extern void pktq_flush(osl_t *osh, struct pktq *pq, bool dir); /* Empty the entire queue */
150extern int pktq_setmax(struct pktq *pq, int max_len);
151
152/* externs */
153/* packet */
154extern uint pktcopy(osl_t *osh, void *p, uint offset, int len, uchar *buf);
155extern uint pkttotlen(osl_t *osh, void *p);
156extern void *pktlast(osl_t *osh, void *p);
157
158/* Get priority from a packet and pass it back in scb (or equiv) */
159extern uint pktsetprio(void *pkt, bool update_vtag);
160#define PKTPRIO_VDSCP 0x100 /* DSCP prio found after VLAN tag */
161#define PKTPRIO_VLAN 0x200 /* VLAN prio found */
162#define PKTPRIO_UPD 0x400 /* DSCP used to update VLAN prio */
163#define PKTPRIO_DSCP 0x800 /* DSCP prio found */
164
165/* string */
166extern int BCMROMFN(bcm_atoi)(char *s);
167extern ulong BCMROMFN(bcm_strtoul)(char *cp, char **endp, uint base);
168extern char *BCMROMFN(bcmstrstr)(char *haystack, char *needle);
169extern char *BCMROMFN(bcmstrcat)(char *dest, const char *src);
170extern char *BCMROMFN(bcmstrncat)(char *dest, const char *src, uint size);
171extern ulong wchar2ascii(char *abuf, ushort *wbuf, ushort wbuflen, ulong abuflen);
172/* ethernet address */
173extern char *bcm_ether_ntoa(struct ether_addr *ea, char *buf);
174extern int BCMROMFN(bcm_ether_atoe)(char *p, struct ether_addr *ea);
175
176/* ip address */
177struct ipv4_addr;
178extern char *bcm_ip_ntoa(struct ipv4_addr *ia, char *buf);
179
180/* delay */
181extern void bcm_mdelay(uint ms);
182/* variable access */
183extern char *getvar(char *vars, const char *name);
184extern int getintvar(char *vars, const char *name);
185extern uint getgpiopin(char *vars, char *pin_name, uint def_pin);
186#ifdef BCMDBG
187extern void prpkt(const char *msg, osl_t *osh, void *p0);
188#endif /* BCMDBG */
189#ifdef BCMPERFSTATS
190extern void bcm_perf_enable(void);
191extern void bcmstats(char *fmt);
192extern void bcmlog(char *fmt, uint a1, uint a2);
193extern void bcmdumplog(char *buf, int size);
194extern int bcmdumplogent(char *buf, uint idx);
195#else
196#define bcm_perf_enable()
197#define bcmstats(fmt)
198#define bcmlog(fmt, a1, a2)
199#define bcmdumplog(buf, size) *buf = '\0'
200#define bcmdumplogent(buf, idx) -1
201#endif /* BCMPERFSTATS */
202extern char *bcm_nvram_vars(uint *length);
203extern int bcm_nvram_cache(void *sbh);
204
205/* Support for sharing code across in-driver iovar implementations.
206 * The intent is that a driver use this structure to map iovar names
207 * to its (private) iovar identifiers, and the lookup function to
208 * find the entry. Macros are provided to map ids and get/set actions
209 * into a single number space for a switch statement.
210 */
211
212/* iovar structure */
213typedef struct bcm_iovar {
214    const char *name; /* name for lookup and display */
215    uint16 varid; /* id for switch */
216    uint16 flags; /* driver-specific flag bits */
217    uint16 type; /* base type of argument */
218    uint16 minlen; /* min length for buffer vars */
219} bcm_iovar_t;
220
221/* varid definitions are per-driver, may use these get/set bits */
222
223/* IOVar action bits for id mapping */
224#define IOV_GET 0 /* Get an iovar */
225#define IOV_SET 1 /* Set an iovar */
226
227/* Varid to actionid mapping */
228#define IOV_GVAL(id) ((id)*2)
229#define IOV_SVAL(id) (((id)*2)+IOV_SET)
230#define IOV_ISSET(actionid) ((actionid & IOV_SET) == IOV_SET)
231
232/* flags are per-driver based on driver attributes */
233
234extern const bcm_iovar_t *bcm_iovar_lookup(const bcm_iovar_t *table, const char *name);
235extern int bcm_iovar_lencheck(const bcm_iovar_t *table, void *arg, int len, bool set);
236
237/* Base type definitions */
238#define IOVT_VOID 0 /* no value (implictly set only) */
239#define IOVT_BOOL 1 /* any value ok (zero/nonzero) */
240#define IOVT_INT8 2 /* integer values are range-checked */
241#define IOVT_UINT8 3 /* unsigned int 8 bits */
242#define IOVT_INT16 4 /* int 16 bits */
243#define IOVT_UINT16 5 /* unsigned int 16 bits */
244#define IOVT_INT32 6 /* int 32 bits */
245#define IOVT_UINT32 7 /* unsigned int 32 bits */
246#define IOVT_BUFFER 8 /* buffer is size-checked as per minlen */
247#define BCM_IOVT_VALID(type) (((unsigned int)(type)) <= IOVT_BUFFER)
248
249/* Initializer for IOV type strings */
250#define BCM_IOV_TYPE_INIT { \
251    "void", \
252    "bool", \
253    "int8", \
254    "uint8", \
255    "int16", \
256    "uint16", \
257    "int32", \
258    "uint32", \
259    "buffer", \
260    "" }
261
262#define BCM_IOVT_IS_INT(type) (\
263    (type == IOVT_BOOL) || \
264    (type == IOVT_INT8) || \
265    (type == IOVT_UINT8) || \
266    (type == IOVT_INT16) || \
267    (type == IOVT_UINT16) || \
268    (type == IOVT_INT32) || \
269    (type == IOVT_UINT32))
270
271/* ** driver/apps-shared section ** */
272
273#define BCME_STRLEN 64 /* Max string length for BCM errors */
274#define VALID_BCMERROR(e) ((e <= 0) && (e >= BCME_LAST))
275
276
277/*
278 * error codes could be added but the defined ones shouldn't be changed/deleted
279 * these error codes are exposed to the user code
280 * when ever a new error code is added to this list
281 * please update errorstring table with the related error string and
282 * update osl files with os specific errorcode map
283*/
284
285#define BCME_OK 0 /* Success */
286#define BCME_ERROR -1 /* Error generic */
287#define BCME_BADARG -2 /* Bad Argument */
288#define BCME_BADOPTION -3 /* Bad option */
289#define BCME_NOTUP -4 /* Not up */
290#define BCME_NOTDOWN -5 /* Not down */
291#define BCME_NOTAP -6 /* Not AP */
292#define BCME_NOTSTA -7 /* Not STA */
293#define BCME_BADKEYIDX -8 /* BAD Key Index */
294#define BCME_RADIOOFF -9 /* Radio Off */
295#define BCME_NOTBANDLOCKED -10 /* Not band locked */
296#define BCME_NOCLK -11 /* No Clock */
297#define BCME_BADRATESET -12 /* BAD Rate valueset */
298#define BCME_BADBAND -13 /* BAD Band */
299#define BCME_BUFTOOSHORT -14 /* Buffer too short */
300#define BCME_BUFTOOLONG -15 /* Buffer too long */
301#define BCME_BUSY -16 /* Busy */
302#define BCME_NOTASSOCIATED -17 /* Not Associated */
303#define BCME_BADSSIDLEN -18 /* Bad SSID len */
304#define BCME_OUTOFRANGECHAN -19 /* Out of Range Channel */
305#define BCME_BADCHAN -20 /* Bad Channel */
306#define BCME_BADADDR -21 /* Bad Address */
307#define BCME_NORESOURCE -22 /* Not Enough Resources */
308#define BCME_UNSUPPORTED -23 /* Unsupported */
309#define BCME_BADLEN -24 /* Bad length */
310#define BCME_NOTREADY -25 /* Not Ready */
311#define BCME_EPERM -26 /* Not Permitted */
312#define BCME_NOMEM -27 /* No Memory */
313#define BCME_ASSOCIATED -28 /* Associated */
314#define BCME_RANGE -29 /* Not In Range */
315#define BCME_NOTFOUND -30 /* Not Found */
316#define BCME_WME_NOT_ENABLED -31 /* WME Not Enabled */
317#define BCME_TSPEC_NOTFOUND -32 /* TSPEC Not Found */
318#define BCME_ACM_NOTSUPPORTED -33 /* ACM Not Supported */
319#define BCME_NOT_WME_ASSOCIATION -34 /* Not WME Association */
320#define BCME_SDIO_ERROR -35 /* SDIO Bus Error */
321#define BCME_DONGLE_DOWN -36 /* Dongle Not Accessible */
322#define BCME_VERSION -37 /* Incorrect version */
323#define BCME_LAST BCME_VERSION
324
325/* These are collection of BCME Error strings */
326#define BCMERRSTRINGTABLE { \
327    "OK", \
328    "Undefined error", \
329    "Bad Argument", \
330    "Bad Option", \
331    "Not up", \
332    "Not down", \
333    "Not AP", \
334    "Not STA", \
335    "Bad Key Index", \
336    "Radio Off", \
337    "Not band locked", \
338    "No clock", \
339    "Bad Rate valueset", \
340    "Bad Band", \
341    "Buffer too short", \
342    "Buffer too long", \
343    "Busy", \
344    "Not Associated", \
345    "Bad SSID len", \
346    "Out of Range Channel", \
347    "Bad Channel", \
348    "Bad Address", \
349    "Not Enough Resources", \
350    "Unsupported", \
351    "Bad length", \
352    "Not Ready", \
353    "Not Permitted", \
354    "No Memory", \
355    "Associated", \
356    "Not In Range", \
357    "Not Found", \
358    "WME Not Enabled", \
359    "TSPEC Not Found", \
360    "ACM Not Supported", \
361    "Not WME Association", \
362    "SDIO Bus Error", \
363    "Dongle Not Accessible", \
364    "Incorrect version" \
365}
366
367#ifndef ABS
368#define ABS(a) (((a) < 0)?-(a):(a))
369#endif /* ABS */
370
371#ifndef MIN
372#define MIN(a, b) (((a) < (b))?(a):(b))
373#endif /* MIN */
374
375#ifndef MAX
376#define MAX(a, b) (((a) > (b))?(a):(b))
377#endif /* MAX */
378
379#define CEIL(x, y) (((x) + ((y)-1)) / (y))
380#define ROUNDUP(x, y) ((((x)+((y)-1))/(y))*(y))
381#define ISALIGNED(a, x) (((a) & ((x)-1)) == 0)
382#define ISPOWEROF2(x) ((((x)-1)&(x)) == 0)
383#define VALID_MASK(mask) !((mask) & ((mask) + 1))
384#ifndef OFFSETOF
385#define OFFSETOF(type, member) ((uint)(uintptr)&((type *)0)->member)
386#endif /* OFFSETOF */
387#ifndef ARRAYSIZE
388#define ARRAYSIZE(a) (sizeof(a)/sizeof(a[0]))
389#endif
390
391/* bit map related macros */
392#ifndef setbit
393#ifndef NBBY /* the BSD family defines NBBY */
394#define NBBY 8 /* 8 bits per byte */
395#endif /* #ifndef NBBY */
396#define setbit(a, i) (((uint8 *)a)[(i)/NBBY] |= 1<<((i)%NBBY))
397#define clrbit(a, i) (((uint8 *)a)[(i)/NBBY] &= ~(1<<((i)%NBBY)))
398#define isset(a, i) (((const uint8 *)a)[(i)/NBBY] & (1<<((i)%NBBY)))
399#define isclr(a, i) ((((const uint8 *)a)[(i)/NBBY] & (1<<((i)%NBBY))) == 0)
400#endif /* setbit */
401
402#define NBITS(type) (sizeof(type) * 8)
403#define NBITVAL(nbits) (1 << (nbits))
404#define MAXBITVAL(nbits) ((1 << (nbits)) - 1)
405#define NBITMASK(nbits) MAXBITVAL(nbits)
406#define MAXNBVAL(nbyte) MAXBITVAL((nbyte) * 8)
407
408/* basic mux operation - can be optimized on several architectures */
409#define MUX(pred, true, false) ((pred) ? (true) : (false))
410
411/* modulo inc/dec - assumes x E [0, bound - 1] */
412#define MODDEC(x, bound) MUX((x) == 0, (bound) - 1, (x) - 1)
413#define MODINC(x, bound) MUX((x) == (bound) - 1, 0, (x) + 1)
414
415/* modulo inc/dec, bound = 2^k */
416#define MODDEC_POW2(x, bound) (((x) - 1) & ((bound) - 1))
417#define MODINC_POW2(x, bound) (((x) + 1) & ((bound) - 1))
418
419/* modulo add/sub - assumes x, y E [0, bound - 1] */
420#define MODADD(x, y, bound) \
421    MUX((x) + (y) >= (bound), (x) + (y) - (bound), (x) + (y))
422#define MODSUB(x, y, bound) \
423    MUX(((int)(x)) - ((int)(y)) < 0, (x) - (y) + (bound), (x) - (y))
424
425/* module add/sub, bound = 2^k */
426#define MODADD_POW2(x, y, bound) (((x) + (y)) & ((bound) - 1))
427#define MODSUB_POW2(x, y, bound) (((x) - (y)) & ((bound) - 1))
428
429/* crc defines */
430#define CRC8_INIT_VALUE 0xff /* Initial CRC8 checksum value */
431#define CRC8_GOOD_VALUE 0x9f /* Good final CRC8 checksum value */
432#define CRC16_INIT_VALUE 0xffff /* Initial CRC16 checksum value */
433#define CRC16_GOOD_VALUE 0xf0b8 /* Good final CRC16 checksum value */
434#define CRC32_INIT_VALUE 0xffffffff /* Initial CRC32 checksum value */
435#define CRC32_GOOD_VALUE 0xdebb20e3 /* Good final CRC32 checksum value */
436
437/* bcm_format_flags() bit description structure */
438typedef struct bcm_bit_desc {
439    uint32 bit;
440    const char* name;
441} bcm_bit_desc_t;
442
443/* tag_ID/length/value_buffer tuple */
444typedef struct bcm_tlv {
445    uint8 id;
446    uint8 len;
447    uint8 data[1];
448} bcm_tlv_t;
449
450/* Check that bcm_tlv_t fits into the given buflen */
451#define bcm_valid_tlv(elt, buflen) ((buflen) >= 2 && (int)(buflen) >= (int)(2 + (elt)->len))
452
453/* buffer length for ethernet address from bcm_ether_ntoa() */
454#define ETHER_ADDR_STR_LEN 18 /* 18-bytes of Ethernet address buffer length */
455
456/* unaligned load and store macros */
457#ifdef IL_BIGENDIAN
458static INLINE uint32
459load32_ua(uint8 *a)
460{
461    return ((a[0] << 24) | (a[1] << 16) | (a[2] << 8) | a[3]);
462}
463
464static INLINE void
465store32_ua(uint8 *a, uint32 v)
466{
467    a[0] = (v >> 24) & 0xff;
468    a[1] = (v >> 16) & 0xff;
469    a[2] = (v >> 8) & 0xff;
470    a[3] = v & 0xff;
471}
472
473static INLINE uint16
474load16_ua(uint8 *a)
475{
476    return ((a[0] << 8) | a[1]);
477}
478
479static INLINE void
480store16_ua(uint8 *a, uint16 v)
481{
482    a[0] = (v >> 8) & 0xff;
483    a[1] = v & 0xff;
484}
485
486#else /* IL_BIGENDIAN */
487
488static INLINE uint32
489load32_ua(uint8 *a)
490{
491    return ((a[3] << 24) | (a[2] << 16) | (a[1] << 8) | a[0]);
492}
493
494static INLINE void
495store32_ua(uint8 *a, uint32 v)
496{
497    a[3] = (v >> 24) & 0xff;
498    a[2] = (v >> 16) & 0xff;
499    a[1] = (v >> 8) & 0xff;
500    a[0] = v & 0xff;
501}
502
503static INLINE uint16
504load16_ua(uint8 *a)
505{
506    return ((a[1] << 8) | a[0]);
507}
508
509static INLINE void
510store16_ua(uint8 *a, uint16 v)
511{
512    a[1] = (v >> 8) & 0xff;
513    a[0] = v & 0xff;
514}
515
516#endif /* IL_BIGENDIAN */
517
518/* externs */
519/* crc */
520extern uint8 BCMROMFN(hndcrc8)(uint8 *p, uint nbytes, uint8 crc);
521extern uint16 BCMROMFN(hndcrc16)(uint8 *p, uint nbytes, uint16 crc);
522extern uint32 BCMROMFN(hndcrc32)(uint8 *p, uint nbytes, uint32 crc);
523/* format/print */
524#ifdef BCMDBG
525extern int bcm_format_flags(const bcm_bit_desc_t *bd, uint32 flags, char* buf, int len);
526extern int bcm_format_hex(char *str, const void *bytes, int len);
527extern void deadbeef(void *p, uint len);
528extern void prhex(const char *msg, uchar *buf, uint len);
529#endif /* BCMDBG */
530extern char *bcm_brev_str(uint16 brev, char *buf);
531extern void printfbig(char *buf);
532
533/* IE parsing */
534extern bcm_tlv_t *BCMROMFN(bcm_next_tlv)(bcm_tlv_t *elt, int *buflen);
535extern bcm_tlv_t *BCMROMFN(bcm_parse_tlvs)(void *buf, int buflen, uint key);
536extern bcm_tlv_t *BCMROMFN(bcm_parse_ordered_tlvs)(void *buf, int buflen, uint key);
537
538/* bcmerror */
539extern const char *bcmerrorstr(int bcmerror);
540
541/* multi-bool data type: set of bools, mbool is true if any is set */
542typedef uint32 mbool;
543#define mboolset(mb, bit) ((mb) |= (bit)) /* set one bool */
544#define mboolclr(mb, bit) ((mb) &= ~(bit)) /* clear one bool */
545#define mboolisset(mb, bit) (((mb) & (bit)) != 0) /* TRUE if one bool is set */
546#define mboolmaskset(mb, mask, val) ((mb) = (((mb) & ~(mask)) | (val)))
547
548/* power conversion */
549extern uint16 BCMROMFN(bcm_qdbm_to_mw)(uint8 qdbm);
550extern uint8 BCMROMFN(bcm_mw_to_qdbm)(uint16 mw);
551
552/* generic datastruct to help dump routines */
553struct fielddesc {
554    const char *nameandfmt;
555    uint32 offset;
556    uint32 len;
557};
558
559extern void bcm_binit(struct bcmstrbuf *b, char *buf, uint size);
560extern int bcm_bprintf(struct bcmstrbuf *b, const char *fmt, ...);
561
562typedef uint32 (*readreg_rtn)(void *arg0, void *arg1, uint32 offset);
563extern uint bcmdumpfields(readreg_rtn func_ptr, void *arg0, void *arg1, struct fielddesc *str,
564                          char *buf, uint32 bufsize);
565
566extern uint bcm_mkiovar(char *name, char *data, uint datalen, char *buf, uint len);
567extern uint BCMROMFN(bcm_bitcount)(uint8 *bitmap, uint bytelength);
568
569#ifdef BCMDBG_PKT /* pkt logging for debugging */
570#define PKTLIST_SIZE 1000
571typedef struct {
572    void *list[PKTLIST_SIZE]; /* List of pointers to packets */
573    uint count; /* Total count of the packets */
574} pktlist_info_t;
575
576extern void pktlist_add(pktlist_info_t *pktlist, void *p);
577extern void pktlist_remove(pktlist_info_t *pktlist, void *p);
578extern char* pktlist_dump(pktlist_info_t *pktlist, char *buf);
579#endif /* BCMDBG_PKT */
580
581#endif /* _bcmutils_h_ */
package/broadcom-wl-old/src/driver/hnddma.c
1/*
2 * Generic Broadcom Home Networking Division (HND) DMA module.
3 * This supports the following chips: BCM42xx, 44xx, 47xx .
4 *
5 * Copyright 2007, Broadcom Corporation
6 * All Rights Reserved.
7 *
8 * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
9 * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
10 * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
11 * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
12 *
13 */
14
15#include <typedefs.h>
16#include <bcmdefs.h>
17#include <osl.h>
18#include "linux_osl.h"
19#include <bcmendian.h>
20#include <sbconfig.h>
21#include "bcmutils.h"
22#include <bcmdevs.h>
23#include <sbutils.h>
24
25#include "sbhnddma.h"
26#include "hnddma.h"
27
28/* debug/trace */
29#ifdef BCMDBG
30#define DMA_ERROR(args) if (!(*di->msg_level & 1)); else printf args
31#define DMA_TRACE(args) if (!(*di->msg_level & 2)); else printf args
32#else
33#define DMA_ERROR(args)
34#define DMA_TRACE(args)
35#endif
36
37/* default dma message level (if input msg_level pointer is null in dma_attach()) */
38static uint dma_msg_level = 0;
39
40#define MAXNAMEL 8 /* 8 char names */
41
42#define DI_INFO(dmah) (dma_info_t *)dmah
43typedef struct osl_dmainfo osldma_t;
44
45/* dma engine software state */
46typedef struct dma_info
47{
48  struct hnddma_pub hnddma; /* exported structure, don't use hnddma_t,
49                 * which could be const
50                 */
51  uint *msg_level; /* message level pointer */
52  char name[MAXNAMEL]; /* callers name for diag msgs */
53
54  void *osh; /* os handle */
55  sb_t *sbh; /* sb handle */
56
57  bool dma64; /* dma64 enabled */
58  bool addrext; /* this dma engine supports DmaExtendedAddrChanges */
59
60  dma32regs_t *d32txregs; /* 32 bits dma tx engine registers */
61  dma32regs_t *d32rxregs; /* 32 bits dma rx engine registers */
62  dma64regs_t *d64txregs; /* 64 bits dma tx engine registers */
63  dma64regs_t *d64rxregs; /* 64 bits dma rx engine registers */
64
65  uint32 dma64align; /* either 8k or 4k depends on number of dd */
66  dma32dd_t *txd32; /* pointer to dma32 tx descriptor ring */
67  dma64dd_t *txd64; /* pointer to dma64 tx descriptor ring */
68  uint ntxd; /* # tx descriptors tunable */
69  uint txin; /* index of next descriptor to reclaim */
70  uint txout; /* index of next descriptor to post */
71  void **txp; /* pointer to parallel array of pointers to packets */
72  osldma_t *tx_dmah; /* DMA TX descriptor ring handle */
73  osldma_t **txp_dmah; /* DMA TX packet data handle */
74  ulong txdpa; /* physical address of descriptor ring */
75  uint txdalign; /* #bytes added to alloc'd mem to align txd */
76  uint txdalloc; /* #bytes allocated for the ring */
77
78  dma32dd_t *rxd32; /* pointer to dma32 rx descriptor ring */
79  dma64dd_t *rxd64; /* pointer to dma64 rx descriptor ring */
80  uint nrxd; /* # rx descriptors tunable */
81  uint rxin; /* index of next descriptor to reclaim */
82  uint rxout; /* index of next descriptor to post */
83  void **rxp; /* pointer to parallel array of pointers to packets */
84  osldma_t *rx_dmah; /* DMA RX descriptor ring handle */
85  osldma_t **rxp_dmah; /* DMA RX packet data handle */
86  ulong rxdpa; /* physical address of descriptor ring */
87  uint rxdalign; /* #bytes added to alloc'd mem to align rxd */
88  uint rxdalloc; /* #bytes allocated for the ring */
89
90  /* tunables */
91  uint rxbufsize; /* rx buffer size in bytes,
92                   not including the extra headroom
93                 */
94  uint nrxpost; /* # rx buffers to keep posted */
95  uint rxoffset; /* rxcontrol offset */
96  uint ddoffsetlow; /* add to get dma address of descriptor ring, low 32 bits */
97  uint ddoffsethigh; /* high 32 bits */
98  uint dataoffsetlow; /* add to get dma address of data buffer, low 32 bits */
99  uint dataoffsethigh; /* high 32 bits */
100} dma_info_t;
101
102#ifdef BCMDMA64
103#define DMA64_ENAB(di) ((di)->dma64)
104#define DMA64_CAP TRUE
105#else
106#define DMA64_ENAB(di) (0)
107#define DMA64_CAP FALSE
108#endif
109
110/* descriptor bumping macros */
111#define XXD(x, n) ((x) & ((n) - 1)) /* faster than %, but n must be power of 2 */
112#define TXD(x) XXD((x), di->ntxd)
113#define RXD(x) XXD((x), di->nrxd)
114#define NEXTTXD(i) TXD(i + 1)
115#define PREVTXD(i) TXD(i - 1)
116#define NEXTRXD(i) RXD(i + 1)
117#define NTXDACTIVE(h, t) TXD(t - h)
118#define NRXDACTIVE(h, t) RXD(t - h)
119
120/* macros to convert between byte offsets and indexes */
121#define B2I(bytes, type) ((bytes) / sizeof(type))
122#define I2B(index, type) ((index) * sizeof(type))
123
124#define PCI32ADDR_HIGH 0xc0000000 /* address[31:30] */
125#define PCI32ADDR_HIGH_SHIFT 30 /* address[31:30] */
126
127
128/* common prototypes */
129static bool _dma_isaddrext (dma_info_t * di);
130static bool _dma_alloc (dma_info_t * di, uint direction);
131static void _dma_detach (dma_info_t * di);
132static void _dma_ddtable_init (dma_info_t * di, uint direction, ulong pa);
133static void _dma_rxinit (dma_info_t * di);
134static void *_dma_rx (dma_info_t * di);
135static void _dma_rxfill (dma_info_t * di);
136static void _dma_rxreclaim (dma_info_t * di);
137static void _dma_rxenable (dma_info_t * di);
138static void *_dma_getnextrxp (dma_info_t * di, bool forceall);
139
140static void _dma_txblock (dma_info_t * di);
141static void _dma_txunblock (dma_info_t * di);
142static uint _dma_txactive (dma_info_t * di);
143
144static void *_dma_peeknexttxp (dma_info_t * di);
145static uintptr _dma_getvar (dma_info_t * di, const char *name);
146static void _dma_counterreset (dma_info_t * di);
147static void _dma_fifoloopbackenable (dma_info_t * di);
148
149/* ** 32 bit DMA prototypes */
150static bool dma32_alloc (dma_info_t * di, uint direction);
151static bool dma32_txreset (dma_info_t * di);
152static bool dma32_rxreset (dma_info_t * di);
153static bool dma32_txsuspendedidle (dma_info_t * di);
154static int dma32_txfast (dma_info_t * di, void *p0, bool commit);
155static void *dma32_getnexttxp (dma_info_t * di, bool forceall);
156static void *dma32_getnextrxp (dma_info_t * di, bool forceall);
157static void dma32_txrotate (dma_info_t * di);
158static bool dma32_rxidle (dma_info_t * di);
159static void dma32_txinit (dma_info_t * di);
160static bool dma32_txenabled (dma_info_t * di);
161static void dma32_txsuspend (dma_info_t * di);
162static void dma32_txresume (dma_info_t * di);
163static bool dma32_txsuspended (dma_info_t * di);
164static void dma32_txreclaim (dma_info_t * di, bool forceall);
165static bool dma32_txstopped (dma_info_t * di);
166static bool dma32_rxstopped (dma_info_t * di);
167static bool dma32_rxenabled (dma_info_t * di);
168static bool _dma32_addrext (osl_t * osh, dma32regs_t * dma32regs);
169
170/* ** 64 bit DMA prototypes and stubs */
171#ifdef BCMDMA64
172static bool dma64_alloc (dma_info_t * di, uint direction);
173static bool dma64_txreset (dma_info_t * di);
174static bool dma64_rxreset (dma_info_t * di);
175static bool dma64_txsuspendedidle (dma_info_t * di);
176static int dma64_txfast (dma_info_t * di, void *p0, bool commit);
177static void *dma64_getnexttxp (dma_info_t * di, bool forceall);
178static void *dma64_getnextrxp (dma_info_t * di, bool forceall);
179static void dma64_txrotate (dma_info_t * di);
180
181static bool dma64_rxidle (dma_info_t * di);
182static void dma64_txinit (dma_info_t * di);
183static bool dma64_txenabled (dma_info_t * di);
184static void dma64_txsuspend (dma_info_t * di);
185static void dma64_txresume (dma_info_t * di);
186static bool dma64_txsuspended (dma_info_t * di);
187static void dma64_txreclaim (dma_info_t * di, bool forceall);
188static bool dma64_txstopped (dma_info_t * di);
189static bool dma64_rxstopped (dma_info_t * di);
190static bool dma64_rxenabled (dma_info_t * di);
191static bool _dma64_addrext (osl_t * osh, dma64regs_t * dma64regs);
192
193#else
194static bool
195dma64_alloc (dma_info_t * di, uint direction)
196{
197  return FALSE;
198}
199static bool
200dma64_txreset (dma_info_t * di)
201{
202  return FALSE;
203}
204static bool
205dma64_rxreset (dma_info_t * di)
206{
207  return FALSE;
208}
209static bool
210dma64_txsuspendedidle (dma_info_t * di)
211{
212  return FALSE;
213}
214static int
215dma64_txfast (dma_info_t * di, void *p0, bool commit)
216{
217  return 0;
218}
219static void *
220dma64_getnexttxp (dma_info_t * di, bool forceall)
221{
222  return NULL;
223}
224static void *
225dma64_getnextrxp (dma_info_t * di, bool forceall)
226{
227  return NULL;
228}
229static void
230dma64_txrotate (dma_info_t * di)
231{
232  return;
233}
234
235static bool
236dma64_rxidle (dma_info_t * di)
237{
238  return FALSE;
239}
240static void
241dma64_txinit (dma_info_t * di)
242{
243  return;
244}
245static bool
246dma64_txenabled (dma_info_t * di)
247{
248  return FALSE;
249}
250static void
251dma64_txsuspend (dma_info_t * di)
252{
253  return;
254}
255static void
256dma64_txresume (dma_info_t * di)
257{
258  return;
259}
260static bool
261dma64_txsuspended (dma_info_t * di)
262{
263  return FALSE;
264}
265static void
266dma64_txreclaim (dma_info_t * di, bool forceall)
267{
268  return;
269}
270static bool
271dma64_txstopped (dma_info_t * di)
272{
273  return FALSE;
274}
275static bool
276dma64_rxstopped (dma_info_t * di)
277{
278  return FALSE;
279}
280static bool
281dma64_rxenabled (dma_info_t * di)
282{
283  return FALSE;
284}
285static bool
286_dma64_addrext (osl_t * osh, dma64regs_t * dma64regs)
287{
288  return FALSE;
289}
290
291#endif /* BCMDMA64 */
292
293#ifdef BCMDBG
294static void dma32_dumpring (dma_info_t * di, struct bcmstrbuf *b,
295                dma32dd_t * ring, uint start, uint end,
296                uint max_num);
297static void dma32_dump (dma_info_t * di, struct bcmstrbuf *b, bool dumpring);
298static void dma32_dumptx (dma_info_t * di, struct bcmstrbuf *b,
299              bool dumpring);
300static void dma32_dumprx (dma_info_t * di, struct bcmstrbuf *b,
301              bool dumpring);
302
303static void dma64_dumpring (dma_info_t * di, struct bcmstrbuf *b,
304                dma64dd_t * ring, uint start, uint end,
305                uint max_num);
306static void dma64_dump (dma_info_t * di, struct bcmstrbuf *b, bool dumpring);
307static void dma64_dumptx (dma_info_t * di, struct bcmstrbuf *b,
308              bool dumpring);
309static void dma64_dumprx (dma_info_t * di, struct bcmstrbuf *b,
310              bool dumpring);
311#endif
312
313
314static di_fcn_t dma64proc = {
315  (di_detach_t) _dma_detach,
316  (di_txinit_t) dma64_txinit,
317  (di_txreset_t) dma64_txreset,
318  (di_txenabled_t) dma64_txenabled,
319  (di_txsuspend_t) dma64_txsuspend,
320  (di_txresume_t) dma64_txresume,
321  (di_txsuspended_t) dma64_txsuspended,
322  (di_txsuspendedidle_t) dma64_txsuspendedidle,
323  (di_txfast_t) dma64_txfast,
324  (di_txstopped_t) dma64_txstopped,
325  (di_txreclaim_t) dma64_txreclaim,
326  (di_getnexttxp_t) dma64_getnexttxp,
327  (di_peeknexttxp_t) _dma_peeknexttxp,
328  (di_txblock_t) _dma_txblock,
329  (di_txunblock_t) _dma_txunblock,
330  (di_txactive_t) _dma_txactive,
331  (di_txrotate_t) dma64_txrotate,
332
333  (di_rxinit_t) _dma_rxinit,
334  (di_rxreset_t) dma64_rxreset,
335  (di_rxidle_t) dma64_rxidle,
336  (di_rxstopped_t) dma64_rxstopped,
337  (di_rxenable_t) _dma_rxenable,
338  (di_rxenabled_t) dma64_rxenabled,
339  (di_rx_t) _dma_rx,
340  (di_rxfill_t) _dma_rxfill,
341  (di_rxreclaim_t) _dma_rxreclaim,
342  (di_getnextrxp_t) _dma_getnextrxp,
343
344  (di_fifoloopbackenable_t) _dma_fifoloopbackenable,
345  (di_getvar_t) _dma_getvar,
346  (di_counterreset_t) _dma_counterreset,
347
348#ifdef BCMDBG
349  (di_dump_t) dma64_dump,
350  (di_dumptx_t) dma64_dumptx,
351  (di_dumprx_t) dma64_dumprx,
352#else
353  NULL,
354  NULL,
355  NULL,
356#endif
357  34
358};
359
360static di_fcn_t dma32proc = {
361  (di_detach_t) _dma_detach,
362  (di_txinit_t) dma32_txinit,
363  (di_txreset_t) dma32_txreset,
364  (di_txenabled_t) dma32_txenabled,
365  (di_txsuspend_t) dma32_txsuspend,
366  (di_txresume_t) dma32_txresume,
367  (di_txsuspended_t) dma32_txsuspended,
368  (di_txsuspendedidle_t) dma32_txsuspendedidle,
369  (di_txfast_t) dma32_txfast,
370  (di_txstopped_t) dma32_txstopped,
371  (di_txreclaim_t) dma32_txreclaim,
372  (di_getnexttxp_t) dma32_getnexttxp,
373  (di_peeknexttxp_t) _dma_peeknexttxp,
374  (di_txblock_t) _dma_txblock,
375  (di_txunblock_t) _dma_txunblock,
376  (di_txactive_t) _dma_txactive,
377  (di_txrotate_t) dma32_txrotate,
378
379  (di_rxinit_t) _dma_rxinit,
380  (di_rxreset_t) dma32_rxreset,
381  (di_rxidle_t) dma32_rxidle,
382  (di_rxstopped_t) dma32_rxstopped,
383  (di_rxenable_t) _dma_rxenable,
384  (di_rxenabled_t) dma32_rxenabled,
385  (di_rx_t) _dma_rx,
386  (di_rxfill_t) _dma_rxfill,
387  (di_rxreclaim_t) _dma_rxreclaim,
388  (di_getnextrxp_t) _dma_getnextrxp,
389
390  (di_fifoloopbackenable_t) _dma_fifoloopbackenable,
391  (di_getvar_t) _dma_getvar,
392  (di_counterreset_t) _dma_counterreset,
393
394#ifdef BCMDBG
395  (di_dump_t) dma32_dump,
396  (di_dumptx_t) dma32_dumptx,
397  (di_dumprx_t) dma32_dumprx,
398#else
399  NULL,
400  NULL,
401  NULL,
402#endif
403  34
404};
405
406hnddma_t *
407dma_attach (osl_t * osh, char *name, sb_t * sbh, void *dmaregstx,
408        void *dmaregsrx, uint ntxd, uint nrxd, uint rxbufsize,
409        uint nrxpost, uint rxoffset, uint * msg_level)
410{
411  dma_info_t *di;
412  uint size;
413
414  /* allocate private info structure */
415  if ((di = MALLOC (osh, sizeof (dma_info_t))) == NULL)
416    {
417#ifdef BCMDBG
418      printf ("dma_attach: out of memory, malloced %d bytes\n",
419          MALLOCED (osh));
420#endif
421      return (NULL);
422    }
423  bzero ((char *) di, sizeof (dma_info_t));
424
425  di->msg_level = msg_level ? msg_level : &dma_msg_level;
426
427  /* old chips w/o sb is no longer supported */
428  ASSERT (sbh != NULL);
429
430  di->dma64 = ((sb_coreflagshi (sbh, 0, 0) & SBTMH_DMA64) == SBTMH_DMA64);
431
432#ifndef BCMDMA64
433  if (di->dma64)
434    {
435      DMA_ERROR (("dma_attach: driver doesn't have the capability to support "
436          "64 bits DMA\n"));
437      goto fail;
438    }
439#endif
440
441  /* check arguments */
442  ASSERT (ISPOWEROF2 (ntxd));
443  ASSERT (ISPOWEROF2 (nrxd));
444  if (nrxd == 0)
445    ASSERT (dmaregsrx == NULL);
446  if (ntxd == 0)
447    ASSERT (dmaregstx == NULL);
448
449
450  /* init dma reg pointer */
451  if (di->dma64)
452    {
453      ASSERT (ntxd <= D64MAXDD);
454      ASSERT (nrxd <= D64MAXDD);
455      di->d64txregs = (dma64regs_t *) dmaregstx;
456      di->d64rxregs = (dma64regs_t *) dmaregsrx;
457
458      di->dma64align = D64RINGALIGN;
459      if ((ntxd < D64MAXDD / 2) && (nrxd < D64MAXDD / 2))
460    {
461      /* for smaller dd table, HW relax the alignment requirement */
462      di->dma64align = D64RINGALIGN / 2;
463    }
464    }
465  else
466    {
467      ASSERT (ntxd <= D32MAXDD);
468      ASSERT (nrxd <= D32MAXDD);
469      di->d32txregs = (dma32regs_t *) dmaregstx;
470      di->d32rxregs = (dma32regs_t *) dmaregsrx;
471    }
472
473  DMA_TRACE (("%s: dma_attach: %s osh %p ntxd %d nrxd %d rxbufsize %d nrxpost %d " "rxoffset %d dmaregstx %p dmaregsrx %p\n", name, (di->dma64 ? "DMA64" : "DMA32"), osh, ntxd, nrxd, rxbufsize, nrxpost, rxoffset, dmaregstx, dmaregsrx));
474
475  /* make a private copy of our callers name */
476  strncpy (di->name, name, MAXNAMEL);
477  di->name[MAXNAMEL - 1] = '\0';
478
479  di->osh = osh;
480  di->sbh = sbh;
481
482  /* save tunables */
483  di->ntxd = ntxd;
484  di->nrxd = nrxd;
485
486  /* the actual dma size doesn't include the extra headroom */
487  if (rxbufsize > BCMEXTRAHDROOM)
488    di->rxbufsize = rxbufsize - BCMEXTRAHDROOM;
489  else
490    di->rxbufsize = rxbufsize;
491
492  di->nrxpost = nrxpost;
493  di->rxoffset = rxoffset;
494
495  /*
496   * figure out the DMA physical address offset for dd and data
497   * for old chips w/o sb, use zero
498   * for new chips w sb,
499   * PCI/PCIE: they map silicon backplace address to zero based memory, need offset
500   * Other bus: use zero
501   * SB_BUS BIGENDIAN kludge: use sdram swapped region for data buffer, not descriptor
502   */
503  di->ddoffsetlow = 0;
504  di->dataoffsetlow = 0;
505  /* for pci bus, add offset */
506  if (sbh->bustype == PCI_BUS)
507    {
508      if ((sbh->buscoretype == SB_PCIE) && di->dma64)
509    {
510      /* pcie with DMA64 */
511      di->ddoffsetlow = 0;
512      di->ddoffsethigh = SB_PCIE_DMA_H32;
513    }
514      else
515    {
516      /* pci(DMA32/DMA64) or pcie with DMA32 */
517      di->ddoffsetlow = SB_PCI_DMA;
518      di->ddoffsethigh = 0;
519    }
520      di->dataoffsetlow = di->ddoffsetlow;
521      di->dataoffsethigh = di->ddoffsethigh;
522    }
523
524#if defined(__mips__) && defined(IL_BIGENDIAN)
525  di->dataoffsetlow = di->dataoffsetlow + SB_SDRAM_SWAPPED;
526#endif
527
528  di->addrext = _dma_isaddrext (di);
529
530  /* allocate tx packet pointer vector */
531  if (ntxd)
532    {
533      size = ntxd * sizeof (void *);
534      if ((di->txp = MALLOC (osh, size)) == NULL)
535    {
536      DMA_ERROR (("%s: dma_attach: out of tx memory, malloced %d bytes\n",
537              di->name, MALLOCED (osh)));
538      goto fail;
539    }
540      bzero ((char *) di->txp, size);
541    }
542
543  /* allocate rx packet pointer vector */
544  if (nrxd)
545    {
546      size = nrxd * sizeof (void *);
547      if ((di->rxp = MALLOC (osh, size)) == NULL)
548    {
549      DMA_ERROR (("%s: dma_attach: out of rx memory, malloced %d bytes\n",
550              di->name, MALLOCED (osh)));
551      goto fail;
552    }
553      bzero ((char *) di->rxp, size);
554    }
555
556  /* allocate transmit descriptor ring, only need ntxd descriptors but it must be aligned */
557  if (ntxd)
558    {
559      if (!_dma_alloc (di, DMA_TX))
560    goto fail;
561    }
562
563  /* allocate receive descriptor ring, only need nrxd descriptors but it must be aligned */
564  if (nrxd)
565    {
566      if (!_dma_alloc (di, DMA_RX))
567    goto fail;
568    }
569
570  if ((di->ddoffsetlow == SB_PCI_DMA) && (di->txdpa > SB_PCI_DMA_SZ)
571      && !di->addrext)
572    {
573      DMA_ERROR (("%s: dma_attach: txdpa 0x%lx: addrext not supported\n",
574          di->name, di->txdpa));
575      goto fail;
576    }
577  if ((di->ddoffsetlow == SB_PCI_DMA) && (di->rxdpa > SB_PCI_DMA_SZ)
578      && !di->addrext)
579    {
580      DMA_ERROR (("%s: dma_attach: rxdpa 0x%lx: addrext not supported\n",
581          di->name, di->rxdpa));
582      goto fail;
583    }
584
585  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));
586
587  /* allocate tx packet pointer vector and DMA mapping vectors */
588  if (ntxd)
589    {
590
591      size = ntxd * sizeof (osldma_t **);
592      if ((di->txp_dmah = (osldma_t **) MALLOC (osh, size)) == NULL)
593    goto fail;
594      bzero ((char *) di->txp_dmah, size);
595    }
596  else
597    di->txp_dmah = NULL;
598
599  /* allocate rx packet pointer vector and DMA mapping vectors */
600  if (nrxd)
601    {
602
603      size = nrxd * sizeof (osldma_t **);
604      if ((di->rxp_dmah = (osldma_t **) MALLOC (osh, size)) == NULL)
605    goto fail;
606      bzero ((char *) di->rxp_dmah, size);
607
608    }
609  else
610    di->rxp_dmah = NULL;
611
612  /* initialize opsvec of function pointers */
613  di->hnddma.di_fn = DMA64_ENAB (di) ? dma64proc : dma32proc;
614
615  return ((hnddma_t *) di);
616
617fail:
618  _dma_detach (di);
619  return (NULL);
620}
621
622/* init the tx or rx descriptor */
623static INLINE void
624dma32_dd_upd (dma_info_t * di, dma32dd_t * ddring, ulong pa, uint outidx,
625          uint32 * flags, uint32 bufcount)
626{
627  /* dma32 uses 32 bits control to fit both flags and bufcounter */
628  *flags = *flags | (bufcount & CTRL_BC_MASK);
629
630  if ((di->dataoffsetlow != SB_PCI_DMA) || !(pa & PCI32ADDR_HIGH))
631    {
632      W_SM (&ddring[outidx].addr, BUS_SWAP32 (pa + di->dataoffsetlow));
633      W_SM (&ddring[outidx].ctrl, BUS_SWAP32 (*flags));
634    }
635  else
636    {
637      /* address extension */
638      uint32 ae;
639      ASSERT (di->addrext);
640      ae = (pa & PCI32ADDR_HIGH) >> PCI32ADDR_HIGH_SHIFT;
641      pa &= ~PCI32ADDR_HIGH;
642
643      *flags |= (ae << CTRL_AE_SHIFT);
644      W_SM (&ddring[outidx].addr, BUS_SWAP32 (pa + di->dataoffsetlow));
645      W_SM (&ddring[outidx].ctrl, BUS_SWAP32 (*flags));
646    }
647}
648
649static INLINE void
650dma64_dd_upd (dma_info_t * di, dma64dd_t * ddring, ulong pa, uint outidx,
651          uint32 * flags, uint32 bufcount)
652{
653  uint32 ctrl2 = bufcount & D64_CTRL2_BC_MASK;
654
655  /* PCI bus with big(>1G) physical address, use address extension */
656  if ((di->dataoffsetlow != SB_PCI_DMA) || !(pa & PCI32ADDR_HIGH))
657    {
658      W_SM (&ddring[outidx].addrlow, BUS_SWAP32 (pa + di->dataoffsetlow));
659      W_SM (&ddring[outidx].addrhigh, BUS_SWAP32 (0 + di->dataoffsethigh));
660      W_SM (&ddring[outidx].ctrl1, BUS_SWAP32 (*flags));
661      W_SM (&ddring[outidx].ctrl2, BUS_SWAP32 (ctrl2));
662    }
663  else
664    {
665      /* address extension */
666      uint32 ae;
667      ASSERT (di->addrext);
668
669      ae = (pa & PCI32ADDR_HIGH) >> PCI32ADDR_HIGH_SHIFT;
670      pa &= ~PCI32ADDR_HIGH;
671
672      ctrl2 |= (ae << D64_CTRL2_AE_SHIFT) & D64_CTRL2_AE;
673      W_SM (&ddring[outidx].addrlow, BUS_SWAP32 (pa + di->dataoffsetlow));
674      W_SM (&ddring[outidx].addrhigh, BUS_SWAP32 (0 + di->dataoffsethigh));
675      W_SM (&ddring[outidx].ctrl1, BUS_SWAP32 (*flags));
676      W_SM (&ddring[outidx].ctrl2, BUS_SWAP32 (ctrl2));
677    }
678}
679
680static bool
681_dma32_addrext (osl_t * osh, dma32regs_t * dma32regs)
682{
683  uint32 w;
684
685  OR_REG (osh, &dma32regs->control, XC_AE);
686  w = R_REG (osh, &dma32regs->control);
687  AND_REG (osh, &dma32regs->control, ~XC_AE);
688  return ((w & XC_AE) == XC_AE);
689}
690
691static bool
692_dma_alloc (dma_info_t * di, uint direction)
693{
694  if (DMA64_ENAB (di))
695    {
696      return dma64_alloc (di, direction);
697    }
698  else
699    {
700      return dma32_alloc (di, direction);
701    }
702}
703
704/* !! may be called with core in reset */
705static void
706_dma_detach (dma_info_t * di)
707{
708  if (di == NULL)
709    return;
710
711  DMA_TRACE (("%s: dma_detach\n", di->name));
712
713  /* shouldn't be here if descriptors are unreclaimed */
714  ASSERT (di->txin == di->txout);
715  ASSERT (di->rxin == di->rxout);
716
717  /* free dma descriptor rings */
718  if (DMA64_ENAB (di))
719    {
720      if (di->txd64)
721    DMA_FREE_CONSISTENT (di->osh,
722                 ((int8 *) (uintptr) di->txd64 - di->txdalign),
723                 di->txdalloc, (di->txdpa - di->txdalign),
724                 &di->tx_dmah);
725      if (di->rxd64)
726    DMA_FREE_CONSISTENT (di->osh,
727                 ((int8 *) (uintptr) di->rxd64 - di->rxdalign),
728                 di->rxdalloc, (di->rxdpa - di->rxdalign),
729                 &di->rx_dmah);
730    }
731  else
732    {
733      if (di->txd32)
734    DMA_FREE_CONSISTENT (di->osh,
735                 ((int8 *) (uintptr) di->txd32 - di->txdalign),
736                 di->txdalloc, (di->txdpa - di->txdalign),
737                 &di->tx_dmah);
738      if (di->rxd32)
739    DMA_FREE_CONSISTENT (di->osh,
740                 ((int8 *) (uintptr) di->rxd32 - di->rxdalign),
741                 di->rxdalloc, (di->rxdpa - di->rxdalign),
742                 &di->rx_dmah);
743    }
744
745  /* free packet pointer vectors */
746  if (di->txp)
747    MFREE (di->osh, (void *) di->txp, (di->ntxd * sizeof (void *)));
748  if (di->rxp)
749    MFREE (di->osh, (void *) di->rxp, (di->nrxd * sizeof (void *)));
750
751  /* free tx packet DMA handles */
752  if (di->txp_dmah)
753    MFREE (di->osh, (void *) di->txp_dmah, di->ntxd * sizeof (osldma_t **));
754
755  /* free rx packet DMA handles */
756  if (di->rxp_dmah)
757    MFREE (di->osh, (void *) di->rxp_dmah, di->nrxd * sizeof (osldma_t **));
758
759  /* free our private info structure */
760  MFREE (di->osh, (void *) di, sizeof (dma_info_t));
761
762}
763
764/* return TRUE if this dma engine supports DmaExtendedAddrChanges, otherwise FALSE */
765static bool
766_dma_isaddrext (dma_info_t * di)
767{
768  if (DMA64_ENAB (di))
769    {
770      /* DMA64 supports full 32 bits or 64 bits. AE is always valid */
771
772      /* not all tx or rx channel are available */
773      if (di->d64txregs != NULL)
774    {
775      if (!_dma64_addrext (di->osh, di->d64txregs))
776        {
777          DMA_ERROR (("%s: _dma_isaddrext: DMA64 tx doesn't have AE set\n", di->name));
778          ASSERT (0);
779        }
780      return TRUE;
781    }
782      else if (di->d64rxregs != NULL)
783    {
784      if (!_dma64_addrext (di->osh, di->d64rxregs))
785        {
786          DMA_ERROR (("%s: _dma_isaddrext: DMA64 rx doesn't have AE set\n", di->name));
787          ASSERT (0);
788        }
789      return TRUE;
790    }
791      return FALSE;
792    }
793  else if (di->d32txregs)
794    return (_dma32_addrext (di->osh, di->d32txregs));
795  else if (di->d32rxregs)
796    return (_dma32_addrext (di->osh, di->d32rxregs));
797  return FALSE;
798}
799
800/* initialize descriptor table base address */
801static void
802_dma_ddtable_init (dma_info_t * di, uint direction, ulong pa)
803{
804  if (DMA64_ENAB (di))
805    {
806
807      if ((di->ddoffsetlow != SB_PCI_DMA) || !(pa & PCI32ADDR_HIGH))
808    {
809      if (direction == DMA_TX)
810        {
811          W_REG (di->osh, &di->d64txregs->addrlow,
812             (pa + di->ddoffsetlow));
813          W_REG (di->osh, &di->d64txregs->addrhigh, di->ddoffsethigh);
814        }
815      else
816        {
817          W_REG (di->osh, &di->d64rxregs->addrlow,
818             (pa + di->ddoffsetlow));
819          W_REG (di->osh, &di->d64rxregs->addrhigh, di->ddoffsethigh);
820        }
821    }
822      else
823    {
824      /* DMA64 32bits address extension */
825      uint32 ae;
826      ASSERT (di->addrext);
827
828      /* shift the high bit(s) from pa to ae */
829      ae = (pa & PCI32ADDR_HIGH) >> PCI32ADDR_HIGH_SHIFT;
830      pa &= ~PCI32ADDR_HIGH;
831
832      if (direction == DMA_TX)
833        {
834          W_REG (di->osh, &di->d64txregs->addrlow,
835             (pa + di->ddoffsetlow));
836          W_REG (di->osh, &di->d64txregs->addrhigh, di->ddoffsethigh);
837          SET_REG (di->osh, &di->d64txregs->control, D64_XC_AE,
838               (ae << D64_XC_AE_SHIFT));
839        }
840      else
841        {
842          W_REG (di->osh, &di->d64rxregs->addrlow,
843             (pa + di->ddoffsetlow));
844          W_REG (di->osh, &di->d64rxregs->addrhigh, di->ddoffsethigh);
845          SET_REG (di->osh, &di->d64rxregs->control, D64_RC_AE,
846               (ae << D64_RC_AE_SHIFT));
847        }
848    }
849
850    }
851  else
852    {
853      if ((di->ddoffsetlow != SB_PCI_DMA) || !(pa & PCI32ADDR_HIGH))
854    {
855      if (direction == DMA_TX)
856        W_REG (di->osh, &di->d32txregs->addr, (pa + di->ddoffsetlow));
857      else
858        W_REG (di->osh, &di->d32rxregs->addr, (pa + di->ddoffsetlow));
859    }
860      else
861    {
862      /* dma32 address extension */
863      uint32 ae;
864      ASSERT (di->addrext);
865
866      /* shift the high bit(s) from pa to ae */
867      ae = (pa & PCI32ADDR_HIGH) >> PCI32ADDR_HIGH_SHIFT;
868      pa &= ~PCI32ADDR_HIGH;
869
870      if (direction == DMA_TX)
871        {
872          W_REG (di->osh, &di->d32txregs->addr, (pa + di->ddoffsetlow));
873          SET_REG (di->osh, &di->d32txregs->control, XC_AE,
874               ae << XC_AE_SHIFT);
875        }
876      else
877        {
878          W_REG (di->osh, &di->d32rxregs->addr, (pa + di->ddoffsetlow));
879          SET_REG (di->osh, &di->d32rxregs->control, RC_AE,
880               ae << RC_AE_SHIFT);
881        }
882    }
883    }
884}
885
886static void
887_dma_fifoloopbackenable (dma_info_t * di)
888{
889  DMA_TRACE (("%s: dma_fifoloopbackenable\n", di->name));
890  if (DMA64_ENAB (di))
891    OR_REG (di->osh, &di->d64txregs->control, D64_XC_LE);
892  else
893    OR_REG (di->osh, &di->d32txregs->control, XC_LE);
894}
895
896static void
897_dma_rxinit (dma_info_t * di)
898{
899  DMA_TRACE (("%s: dma_rxinit\n", di->name));
900
901  if (di->nrxd == 0)
902    return;
903
904  di->rxin = di->rxout = 0;
905
906  /* clear rx descriptor ring */
907  if (DMA64_ENAB (di))
908    BZERO_SM ((void *) (uintptr) di->rxd64, (di->nrxd * sizeof (dma64dd_t)));
909  else
910    BZERO_SM ((void *) (uintptr) di->rxd32, (di->nrxd * sizeof (dma32dd_t)));
911
912  _dma_rxenable (di);
913  _dma_ddtable_init (di, DMA_RX, di->rxdpa);
914}
915
916static void
917_dma_rxenable (dma_info_t * di)
918{
919  DMA_TRACE (("%s: dma_rxenable\n", di->name));
920
921  if (DMA64_ENAB (di))
922    W_REG (di->osh, &di->d64rxregs->control,
923       ((di->rxoffset << D64_RC_RO_SHIFT) | D64_RC_RE));
924  else
925    W_REG (di->osh, &di->d32rxregs->control,
926       ((di->rxoffset << RC_RO_SHIFT) | RC_RE));
927}
928
929/* !! rx entry routine, returns a pointer to the next frame received,
930 * or NULL if there are no more
931 */
932static void *
933_dma_rx (dma_info_t * di)
934{
935  void *p;
936  uint len;
937  int skiplen = 0;
938
939  while ((p = _dma_getnextrxp (di, FALSE)))
940    {
941      /* skip giant packets which span multiple rx descriptors */
942      if (skiplen > 0)
943    {
944      skiplen -= di->rxbufsize;
945      if (skiplen < 0)
946        skiplen = 0;
947      PKTFREE (di->osh, p, FALSE);
948      continue;
949    }
950
951      len = ltoh16 (*(uint16 *) (PKTDATA (di->osh, p)));
952      DMA_TRACE (("%s: dma_rx len %d\n", di->name, len));
953
954      /* bad frame length check */
955      if (len > (di->rxbufsize - di->rxoffset))
956    {
957      DMA_ERROR (("%s: dma_rx: bad frame length (%d)\n", di->name, len));
958      if (len > 0)
959        skiplen = len - (di->rxbufsize - di->rxoffset);
960      PKTFREE (di->osh, p, FALSE);
961      di->hnddma.rxgiants++;
962      continue;
963    }
964
965      /* set actual length */
966      PKTSETLEN (di->osh, p, (di->rxoffset + len));
967
968      break;
969    }
970
971  return (p);
972}
973
974/* post receive buffers */
975static void
976_dma_rxfill (dma_info_t * di)
977{
978  void *p;
979  uint rxin, rxout;
980  uint32 flags = 0;
981  uint n;
982  uint i;
983  uint32 pa;
984  uint extra_offset = 0;
985
986  /*
987   * Determine how many receive buffers we're lacking
988   * from the full complement, allocate, initialize,
989   * and post them, then update the chip rx lastdscr.
990   */
991
992  rxin = di->rxin;
993  rxout = di->rxout;
994
995  n = di->nrxpost - NRXDACTIVE (rxin, rxout);
996
997  DMA_TRACE (("%s: dma_rxfill: post %d\n", di->name, n));
998
999  if (di->rxbufsize > BCMEXTRAHDROOM)
1000    extra_offset = BCMEXTRAHDROOM;
1001
1002  for (i = 0; i < n; i++)
1003    {
1004      /* the di->rxbufsize doesn't include the extra headroom, we need to add it to the
1005         size to be allocated
1006       */
1007      if ((p = PKTGET (di->osh, di->rxbufsize + extra_offset, FALSE)) == NULL)
1008    {
1009      DMA_ERROR (("%s: dma_rxfill: out of rxbufs\n", di->name));
1010      di->hnddma.rxnobuf++;
1011      break;
1012    }
1013      /* reserve an extra headroom, if applicable */
1014      if (extra_offset)
1015    PKTPULL (di->osh, p, extra_offset);
1016
1017      /* Do a cached write instead of uncached write since DMA_MAP
1018       * will flush the cache.
1019       */
1020      *(uint32 *) (PKTDATA (di->osh, p)) = 0;
1021
1022      pa = (uint32) DMA_MAP (di->osh, PKTDATA (di->osh, p),
1023                 di->rxbufsize, DMA_RX, p, &di->rxp_dmah[rxout]);
1024
1025      ASSERT (ISALIGNED (pa, 4));
1026
1027      /* save the free packet pointer */
1028      ASSERT (di->rxp[rxout] == NULL);
1029      di->rxp[rxout] = p;
1030
1031      /* reset flags for each descriptor */
1032      flags = 0;
1033      if (DMA64_ENAB (di))
1034    {
1035      if (rxout == (di->nrxd - 1))
1036        flags = D64_CTRL1_EOT;
1037
1038      dma64_dd_upd (di, di->rxd64, pa, rxout, &flags, di->rxbufsize);
1039    }
1040      else
1041    {
1042      if (rxout == (di->nrxd - 1))
1043        flags = CTRL_EOT;
1044
1045      dma32_dd_upd (di, di->rxd32, pa, rxout, &flags, di->rxbufsize);
1046    }
1047      rxout = NEXTRXD (rxout);
1048    }
1049
1050  di->rxout = rxout;
1051
1052  /* update the chip lastdscr pointer */
1053  if (DMA64_ENAB (di))
1054    {
1055      W_REG (di->osh, &di->d64rxregs->ptr, I2B (rxout, dma64dd_t));
1056    }
1057  else
1058    {
1059      W_REG (di->osh, &di->d32rxregs->ptr, I2B (rxout, dma32dd_t));
1060    }
1061}
1062
1063/* like getnexttxp but no reclaim */
1064static void *
1065_dma_peeknexttxp (dma_info_t * di)
1066{
1067  uint end, i;
1068
1069  if (di->ntxd == 0)
1070    return (NULL);
1071
1072  if (DMA64_ENAB (di))
1073    {
1074      end =
1075    B2I (R_REG (di->osh, &di->d64txregs->status0) & D64_XS0_CD_MASK,
1076         dma64dd_t);
1077    }
1078  else
1079    {
1080      end =
1081    B2I (R_REG (di->osh, &di->d32txregs->status) & XS_CD_MASK, dma32dd_t);
1082    }
1083
1084  for (i = di->txin; i != end; i = NEXTTXD (i))
1085    if (di->txp[i])
1086      return (di->txp[i]);
1087
1088  return (NULL);
1089}
1090
1091static void
1092_dma_rxreclaim (dma_info_t * di)
1093{
1094  void *p;
1095
1096  /* "unused local" warning suppression for OSLs that
1097   * define PKTFREE() without using the di->osh arg
1098   */
1099  di = di;
1100
1101  DMA_TRACE (("%s: dma_rxreclaim\n", di->name));
1102
1103  while ((p = _dma_getnextrxp (di, TRUE)))
1104    PKTFREE (di->osh, p, FALSE);
1105}
1106
1107static void *
1108_dma_getnextrxp (dma_info_t * di, bool forceall)
1109{
1110  if (di->nrxd == 0)
1111    return (NULL);
1112
1113  if (DMA64_ENAB (di))
1114    {
1115      return dma64_getnextrxp (di, forceall);
1116    }
1117  else
1118    {
1119      return dma32_getnextrxp (di, forceall);
1120    }
1121}
1122
1123static void
1124_dma_txblock (dma_info_t * di)
1125{
1126  di->hnddma.txavail = 0;
1127}
1128
1129static void
1130_dma_txunblock (dma_info_t * di)
1131{
1132  di->hnddma.txavail = di->ntxd - NTXDACTIVE (di->txin, di->txout) - 1;
1133}
1134
1135static uint
1136_dma_txactive (dma_info_t * di)
1137{
1138  return (NTXDACTIVE (di->txin, di->txout));
1139}
1140
1141static void
1142_dma_counterreset (dma_info_t * di)
1143{
1144  /* reset all software counter */
1145  di->hnddma.rxgiants = 0;
1146  di->hnddma.rxnobuf = 0;
1147  di->hnddma.txnobuf = 0;
1148}
1149
1150/* get the address of the var in order to change later */
1151static uintptr
1152_dma_getvar (dma_info_t * di, const char *name)
1153{
1154  if (!strcmp (name, "&txavail"))
1155    return ((uintptr) & (di->hnddma.txavail));
1156  else
1157    {
1158      ASSERT (0);
1159    }
1160  return (0);
1161}
1162
1163void
1164dma_txpioloopback (osl_t * osh, dma32regs_t * regs)
1165{
1166  OR_REG (osh, &regs->control, XC_LE);
1167}
1168
1169#ifdef BCMDBG
1170static void
1171dma32_dumpring (dma_info_t * di, struct bcmstrbuf *b, dma32dd_t * ring,
1172        uint start, uint end, uint max_num)
1173{
1174  uint i;
1175
1176  for (i = start; i != end; i = XXD ((i + 1), max_num))
1177    {
1178      /* in the format of high->low 8 bytes */
1179      bcm_bprintf (b, "ring index %d: 0x%x %x\n", i, ring[i].addr,
1180           ring[i].ctrl);
1181    }
1182}
1183
1184static void
1185dma32_dumptx (dma_info_t * di, struct bcmstrbuf *b, bool dumpring)
1186{
1187  if (di->ntxd == 0)
1188    return;
1189
1190  bcm_bprintf (b, "DMA32: txd32 %p txdpa 0x%lx txp %p txin %d txout %d "
1191           "txavail %d\n", di->txd32, di->txdpa, di->txp, di->txin,
1192           di->txout, di->hnddma.txavail);
1193
1194  bcm_bprintf (b, "xmtcontrol 0x%x xmtaddr 0x%x xmtptr 0x%x xmtstatus 0x%x\n",
1195           R_REG (di->osh, &di->d32txregs->control),
1196           R_REG (di->osh, &di->d32txregs->addr),
1197           R_REG (di->osh, &di->d32txregs->ptr),
1198           R_REG (di->osh, &di->d32txregs->status));
1199
1200  if (dumpring && di->txd32)
1201    dma32_dumpring (di, b, di->txd32, di->txin, di->txout, di->ntxd);
1202}
1203
1204static void
1205dma32_dumprx (dma_info_t * di, struct bcmstrbuf *b, bool dumpring)
1206{
1207  if (di->nrxd == 0)
1208    return;
1209
1210  bcm_bprintf (b, "DMA32: rxd32 %p rxdpa 0x%lx rxp %p rxin %d rxout %d\n",
1211           di->rxd32, di->rxdpa, di->rxp, di->rxin, di->rxout);
1212
1213  bcm_bprintf (b, "rcvcontrol 0x%x rcvaddr 0x%x rcvptr 0x%x rcvstatus 0x%x\n",
1214           R_REG (di->osh, &di->d32rxregs->control),
1215           R_REG (di->osh, &di->d32rxregs->addr),
1216           R_REG (di->osh, &di->d32rxregs->ptr),
1217           R_REG (di->osh, &di->d32rxregs->status));
1218  if (di->rxd32 && dumpring)
1219    dma32_dumpring (di, b, di->rxd32, di->rxin, di->rxout, di->nrxd);
1220}
1221
1222static void
1223dma32_dump (dma_info_t * di, struct bcmstrbuf *b, bool dumpring)
1224{
1225  dma32_dumptx (di, b, dumpring);
1226  dma32_dumprx (di, b, dumpring);
1227}
1228
1229static void
1230dma64_dumpring (dma_info_t * di, struct bcmstrbuf *b, dma64dd_t * ring,
1231        uint start, uint end, uint max_num)
1232{
1233  uint i;
1234
1235  for (i = start; i != end; i = XXD ((i + 1), max_num))
1236    {
1237      /* in the format of high->low 16 bytes */
1238      bcm_bprintf (b, "ring index %d: 0x%x %x %x %x\n",
1239           i, ring[i].addrhigh, ring[i].addrlow, ring[i].ctrl2,
1240           ring[i].ctrl1);
1241    }
1242}
1243
1244static void
1245dma64_dumptx (dma_info_t * di, struct bcmstrbuf *b, bool dumpring)
1246{
1247  if (di->ntxd == 0)
1248    return;
1249
1250  bcm_bprintf (b, "DMA64: txd64 %p txdpa 0x%lx txp %p txin %d txout %d "
1251           "txavail %d\n", di->txd64, di->txdpa, di->txp, di->txin,
1252           di->txout, di->hnddma.txavail);
1253
1254  bcm_bprintf (b, "xmtcontrol 0x%x xmtaddrlow 0x%x xmtaddrhigh 0x%x "
1255           "xmtptr 0x%x xmtstatus0 0x%x xmtstatus1 0x%x\n",
1256           R_REG (di->osh, &di->d64txregs->control),
1257           R_REG (di->osh, &di->d64txregs->addrlow),
1258           R_REG (di->osh, &di->d64txregs->addrhigh),
1259           R_REG (di->osh, &di->d64txregs->ptr),
1260           R_REG (di->osh, &di->d64txregs->status0),
1261           R_REG (di->osh, &di->d64txregs->status1));
1262
1263  if (dumpring && di->txd64)
1264    {
1265      dma64_dumpring (di, b, di->txd64, di->txin, di->txout, di->ntxd);
1266    }
1267}
1268
1269static void
1270dma64_dumprx (dma_info_t * di, struct bcmstrbuf *b, bool dumpring)
1271{
1272  if (di->nrxd == 0)
1273    return;
1274
1275  bcm_bprintf (b, "DMA64: rxd64 %p rxdpa 0x%lx rxp %p rxin %d rxout %d\n",
1276           di->rxd64, di->rxdpa, di->rxp, di->rxin, di->rxout);
1277
1278  bcm_bprintf (b, "rcvcontrol 0x%x rcvaddrlow 0x%x rcvaddrhigh 0x%x rcvptr "
1279           "0x%x rcvstatus0 0x%x rcvstatus1 0x%x\n",
1280           R_REG (di->osh, &di->d64rxregs->control),
1281           R_REG (di->osh, &di->d64rxregs->addrlow),
1282           R_REG (di->osh, &di->d64rxregs->addrhigh),
1283           R_REG (di->osh, &di->d64rxregs->ptr),
1284           R_REG (di->osh, &di->d64rxregs->status0),
1285           R_REG (di->osh, &di->d64rxregs->status1));
1286  if (di->rxd64 && dumpring)
1287    {
1288      dma64_dumpring (di, b, di->rxd64, di->rxin, di->rxout, di->nrxd);
1289    }
1290}
1291
1292static void
1293dma64_dump (dma_info_t * di, struct bcmstrbuf *b, bool dumpring)
1294{
1295  dma64_dumptx (di, b, dumpring);
1296  dma64_dumprx (di, b, dumpring);
1297}
1298
1299#endif /* BCMDBG */
1300
1301
1302/* 32 bits DMA functions */
1303static void
1304dma32_txinit (dma_info_t * di)
1305{
1306  DMA_TRACE (("%s: dma_txinit\n", di->name));
1307
1308  if (di->ntxd == 0)
1309    return;
1310
1311  di->txin = di->txout = 0;
1312  di->hnddma.txavail = di->ntxd - 1;
1313
1314  /* clear tx descriptor ring */
1315  BZERO_SM ((void *) (uintptr) di->txd32, (di->ntxd * sizeof (dma32dd_t)));
1316  W_REG (di->osh, &di->d32txregs->control, XC_XE);
1317  _dma_ddtable_init (di, DMA_TX, di->txdpa);
1318}
1319
1320static bool
1321dma32_txenabled (dma_info_t * di)
1322{
1323  uint32 xc;
1324
1325  /* If the chip is dead, it is not enabled :-) */
1326  xc = R_REG (di->osh, &di->d32txregs->control);
1327  return ((xc != 0xffffffff) && (xc & XC_XE));
1328}
1329
1330static void
1331dma32_txsuspend (dma_info_t * di)
1332{
1333  DMA_TRACE (("%s: dma_txsuspend\n", di->name));
1334
1335  if (di->ntxd == 0)
1336    return;
1337
1338  OR_REG (di->osh, &di->d32txregs->control, XC_SE);
1339}
1340
1341static void
1342dma32_txresume (dma_info_t * di)
1343{
1344  DMA_TRACE (("%s: dma_txresume\n", di->name));
1345
1346  if (di->ntxd == 0)
1347    return;
1348
1349  AND_REG (di->osh, &di->d32txregs->control, ~XC_SE);
1350}
1351
1352static bool
1353dma32_txsuspended (dma_info_t * di)
1354{
1355  return (di->ntxd == 0)
1356    || ((R_REG (di->osh, &di->d32txregs->control) & XC_SE) == XC_SE);
1357}
1358
1359static void
1360dma32_txreclaim (dma_info_t * di, bool forceall)
1361{
1362  void *p;
1363
1364  DMA_TRACE (("%s: dma_txreclaim %s\n", di->name, forceall ? "all" : ""));
1365
1366  while ((p = dma32_getnexttxp (di, forceall)))
1367    PKTFREE (di->osh, p, TRUE);
1368}
1369
1370static bool
1371dma32_txstopped (dma_info_t * di)
1372{
1373  return ((R_REG (di->osh, &di->d32txregs->status) & XS_XS_MASK) ==
1374      XS_XS_STOPPED);
1375}
1376
1377static bool
1378dma32_rxstopped (dma_info_t * di)
1379{
1380  return ((R_REG (di->osh, &di->d32rxregs->status) & RS_RS_MASK) ==
1381      RS_RS_STOPPED);
1382}
1383
1384static bool
1385dma32_alloc (dma_info_t * di, uint direction)
1386{
1387  uint size;
1388  uint ddlen;
1389  void *va;
1390
1391  ddlen = sizeof (dma32dd_t);
1392
1393  size = (direction == DMA_TX) ? (di->ntxd * ddlen) : (di->nrxd * ddlen);
1394
1395  if (!ISALIGNED (DMA_CONSISTENT_ALIGN, D32RINGALIGN))
1396    size += D32RINGALIGN;
1397
1398
1399  if (direction == DMA_TX)
1400    {
1401      if ((va =
1402       DMA_ALLOC_CONSISTENT (di->osh, size, &di->txdpa,
1403                 &di->tx_dmah)) == NULL)
1404    {
1405      DMA_ERROR (("%s: dma_attach: DMA_ALLOC_CONSISTENT(ntxd) failed\n",
1406              di->name));
1407      return FALSE;
1408    }
1409
1410      di->txd32 = (dma32dd_t *) ROUNDUP ((uintptr) va, D32RINGALIGN);
1411      di->txdalign = (uint) ((int8 *) (uintptr) di->txd32 - (int8 *) va);
1412      di->txdpa += di->txdalign;
1413      di->txdalloc = size;
1414      ASSERT (ISALIGNED ((uintptr) di->txd32, D32RINGALIGN));
1415    }
1416  else
1417    {
1418      if ((va =
1419       DMA_ALLOC_CONSISTENT (di->osh, size, &di->rxdpa,
1420                 &di->rx_dmah)) == NULL)
1421    {
1422      DMA_ERROR (("%s: dma_attach: DMA_ALLOC_CONSISTENT(nrxd) failed\n",
1423              di->name));
1424      return FALSE;
1425    }
1426      di->rxd32 = (dma32dd_t *) ROUNDUP ((uintptr) va, D32RINGALIGN);
1427      di->rxdalign = (uint) ((int8 *) (uintptr) di->rxd32 - (int8 *) va);
1428      di->rxdpa += di->rxdalign;
1429      di->rxdalloc = size;
1430      ASSERT (ISALIGNED ((uintptr) di->rxd32, D32RINGALIGN));
1431    }
1432
1433  return TRUE;
1434}
1435
1436static bool
1437dma32_txreset (dma_info_t * di)
1438{
1439  uint32 status;
1440
1441  if (di->ntxd == 0)
1442    return TRUE;
1443
1444  /* suspend tx DMA first */
1445  W_REG (di->osh, &di->d32txregs->control, XC_SE);
1446  SPINWAIT (((status = (R_REG (di->osh, &di->d32txregs->status) & XS_XS_MASK))
1447         != XS_XS_DISABLED) &&
1448        (status != XS_XS_IDLE) && (status != XS_XS_STOPPED), (10000));
1449
1450  W_REG (di->osh, &di->d32txregs->control, 0);
1451  SPINWAIT (((status = (R_REG (di->osh,
1452                   &di->d32txregs->status) & XS_XS_MASK)) !=
1453         XS_XS_DISABLED), 10000);
1454
1455  /* wait for the last transaction to complete */
1456  OSL_DELAY (300);
1457
1458  return (status == XS_XS_DISABLED);
1459}
1460
1461static bool
1462dma32_rxidle (dma_info_t * di)
1463{
1464  DMA_TRACE (("%s: dma_rxidle\n", di->name));
1465
1466  if (di->nrxd == 0)
1467    return TRUE;
1468
1469  return ((R_REG (di->osh, &di->d32rxregs->status) & RS_CD_MASK) ==
1470      R_REG (di->osh, &di->d32rxregs->ptr));
1471}
1472
1473static bool
1474dma32_rxreset (dma_info_t * di)
1475{
1476  uint32 status;
1477
1478  if (di->nrxd == 0)
1479    return TRUE;
1480
1481  W_REG (di->osh, &di->d32rxregs->control, 0);
1482  SPINWAIT (((status = (R_REG (di->osh,
1483                   &di->d32rxregs->status) & RS_RS_MASK)) !=
1484         RS_RS_DISABLED), 10000);
1485
1486  return (status == RS_RS_DISABLED);
1487}
1488
1489static bool
1490dma32_rxenabled (dma_info_t * di)
1491{
1492  uint32 rc;
1493
1494  rc = R_REG (di->osh, &di->d32rxregs->control);
1495  return ((rc != 0xffffffff) && (rc & RC_RE));
1496}
1497
1498static bool
1499dma32_txsuspendedidle (dma_info_t * di)
1500{
1501  if (di->ntxd == 0)
1502    return TRUE;
1503
1504  if (!(R_REG (di->osh, &di->d32txregs->control) & XC_SE))
1505    return 0;
1506
1507  if ((R_REG (di->osh, &di->d32txregs->status) & XS_XS_MASK) != XS_XS_IDLE)
1508    return 0;
1509
1510  OSL_DELAY (2);
1511  return ((R_REG (di->osh, &di->d32txregs->status) & XS_XS_MASK) ==
1512      XS_XS_IDLE);
1513}
1514
1515/* !! tx entry routine
1516 * supports full 32bit dma engine buffer addressing so
1517 * dma buffers can cross 4 Kbyte page boundaries.
1518 */
1519static int
1520dma32_txfast (dma_info_t * di, void *p0, bool commit)
1521{
1522  void *p, *next;
1523  uchar *data;
1524  uint len;
1525  uint txout;
1526  uint32 flags = 0;
1527  uint32 pa;
1528
1529  DMA_TRACE (("%s: dma_txfast\n", di->name));
1530
1531  txout = di->txout;
1532
1533  /*
1534   * Walk the chain of packet buffers
1535   * allocating and initializing transmit descriptor entries.
1536   */
1537  for (p = p0; p; p = next)
1538    {
1539      data = PKTDATA (di->osh, p);
1540      len = PKTLEN (di->osh, p);
1541      next = PKTNEXT (di->osh, p);
1542
1543      /* return nonzero if out of tx descriptors */
1544      if (NEXTTXD (txout) == di->txin)
1545    goto outoftxd;
1546
1547      if (len == 0)
1548    continue;
1549
1550      /* get physical address of buffer start */
1551      pa =
1552    (uint32) DMA_MAP (di->osh, data, len, DMA_TX, p,
1553              &di->txp_dmah[txout]);
1554
1555      flags = 0;
1556      if (p == p0)
1557    flags |= CTRL_SOF;
1558      if (next == NULL)
1559    flags |= (CTRL_IOC | CTRL_EOF);
1560      if (txout == (di->ntxd - 1))
1561    flags |= CTRL_EOT;
1562
1563      dma32_dd_upd (di, di->txd32, pa, txout, &flags, len);
1564      ASSERT (di->txp[txout] == NULL);
1565
1566      txout = NEXTTXD (txout);
1567    }
1568
1569  /* if last txd eof not set, fix it */
1570  if (!(flags & CTRL_EOF))
1571    W_SM (&di->txd32[PREVTXD (txout)].ctrl,
1572      BUS_SWAP32 (flags | CTRL_IOC | CTRL_EOF));
1573
1574  /* save the packet */
1575  di->txp[PREVTXD (txout)] = p0;
1576
1577  /* bump the tx descriptor index */
1578  di->txout = txout;
1579
1580  /* kick the chip */
1581  if (commit)
1582    W_REG (di->osh, &di->d32txregs->ptr, I2B (txout, dma32dd_t));
1583
1584  /* tx flow control */
1585  di->hnddma.txavail = di->ntxd - NTXDACTIVE (di->txin, di->txout) - 1;
1586
1587  return (0);
1588
1589outoftxd:
1590  DMA_ERROR (("%s: dma_txfast: out of txds\n", di->name));
1591  PKTFREE (di->osh, p0, TRUE);
1592  di->hnddma.txavail = 0;
1593  di->hnddma.txnobuf++;
1594  return (-1);
1595}
1596
1597/*
1598 * Reclaim next completed txd (txds if using chained buffers) and
1599 * return associated packet.
1600 * If 'force' is true, reclaim txd(s) and return associated packet
1601 * regardless of the value of the hardware "curr" pointer.
1602 */
1603static void *
1604dma32_getnexttxp (dma_info_t * di, bool forceall)
1605{
1606  uint start, end, i;
1607  void *txp;
1608
1609  DMA_TRACE (("%s: dma_getnexttxp %s\n", di->name, forceall ? "all" : ""));
1610
1611  if (di->ntxd == 0)
1612    return (NULL);
1613
1614  txp = NULL;
1615
1616  start = di->txin;
1617  if (forceall)
1618    end = di->txout;
1619  else
1620    end =
1621      B2I (R_REG (di->osh, &di->d32txregs->status) & XS_CD_MASK, dma32dd_t);
1622
1623  if ((start == 0) && (end > di->txout))
1624    goto bogus;
1625
1626  for (i = start; i != end && !txp; i = NEXTTXD (i))
1627    {
1628      DMA_UNMAP (di->osh,
1629         (BUS_SWAP32 (R_SM (&di->txd32[i].addr)) - di->dataoffsetlow),
1630         (BUS_SWAP32 (R_SM (&di->txd32[i].ctrl)) & CTRL_BC_MASK),
1631         DMA_TX, di->txp[i], &di->txp_dmah[i]);
1632
1633      W_SM (&di->txd32[i].addr, 0xdeadbeef);
1634      txp = di->txp[i];
1635      di->txp[i] = NULL;
1636    }
1637
1638  di->txin = i;
1639
1640  /* tx flow control */
1641  di->hnddma.txavail = di->ntxd - NTXDACTIVE (di->txin, di->txout) - 1;
1642
1643  return (txp);
1644
1645bogus:
1646/*
1647    DMA_ERROR(("dma_getnexttxp: bogus curr: start %d end %d txout %d force %d\n",
1648        start, end, di->txout, forceall));
1649*/
1650  return (NULL);
1651}
1652
1653static void *
1654dma32_getnextrxp (dma_info_t * di, bool forceall)
1655{
1656  uint i;
1657  void *rxp;
1658
1659  /* if forcing, dma engine must be disabled */
1660  ASSERT (!forceall || !dma32_rxenabled (di));
1661
1662  i = di->rxin;
1663
1664  /* return if no packets posted */
1665  if (i == di->rxout)
1666    return (NULL);
1667
1668  /* ignore curr if forceall */
1669  if (!forceall
1670      && (i ==
1671      B2I (R_REG (di->osh, &di->d32rxregs->status) & RS_CD_MASK,
1672           dma32dd_t)))
1673    return (NULL);
1674
1675  /* get the packet pointer that corresponds to the rx descriptor */
1676  rxp = di->rxp[i];
1677  ASSERT (rxp);
1678  di->rxp[i] = NULL;
1679
1680  /* clear this packet from the descriptor ring */
1681  DMA_UNMAP (di->osh,
1682         (BUS_SWAP32 (R_SM (&di->rxd32[i].addr)) - di->dataoffsetlow),
1683         di->rxbufsize, DMA_RX, rxp, &di->rxp_dmah[i]);
1684
1685  W_SM (&di->rxd32[i].addr, 0xdeadbeef);
1686
1687  di->rxin = NEXTRXD (i);
1688
1689  return (rxp);
1690}
1691
1692/*
1693 * Rotate all active tx dma ring entries "forward" by (ActiveDescriptor - txin).
1694 */
1695static void
1696dma32_txrotate (dma_info_t * di)
1697{
1698  uint ad;
1699  uint nactive;
1700  uint rot;
1701  uint old, new;
1702  uint32 w;
1703  uint first, last;
1704
1705  ASSERT (dma32_txsuspendedidle (di));
1706
1707  nactive = _dma_txactive (di);
1708  ad =
1709    B2I (((R_REG (di->osh, &di->d32txregs->status) & XS_AD_MASK) >>
1710      XS_AD_SHIFT), dma32dd_t);
1711  rot = TXD (ad - di->txin);
1712
1713  ASSERT (rot < di->ntxd);
1714
1715  /* full-ring case is a lot harder - don't worry about this */
1716  if (rot >= (di->ntxd - nactive))
1717    {
1718      DMA_ERROR (("%s: dma_txrotate: ring full - punt\n", di->name));
1719      return;
1720    }
1721
1722  first = di->txin;
1723  last = PREVTXD (di->txout);
1724
1725  /* move entries starting at last and moving backwards to first */
1726  for (old = last; old != PREVTXD (first); old = PREVTXD (old))
1727    {
1728      new = TXD (old + rot);
1729
1730      /*
1731       * Move the tx dma descriptor.
1732       * EOT is set only in the last entry in the ring.
1733       */
1734      w = BUS_SWAP32 (R_SM (&di->txd32[old].ctrl)) & ~CTRL_EOT;
1735      if (new == (di->ntxd - 1))
1736    w |= CTRL_EOT;
1737      W_SM (&di->txd32[new].ctrl, BUS_SWAP32 (w));
1738      W_SM (&di->txd32[new].addr, R_SM (&di->txd32[old].addr));
1739
1740      /* zap the old tx dma descriptor address field */
1741      W_SM (&di->txd32[old].addr, BUS_SWAP32 (0xdeadbeef));
1742
1743      /* move the corresponding txp[] entry */
1744      ASSERT (di->txp[new] == NULL);
1745      di->txp[new] = di->txp[old];
1746      di->txp[old] = NULL;
1747    }
1748
1749  /* update txin and txout */
1750  di->txin = ad;
1751  di->txout = TXD (di->txout + rot);
1752  di->hnddma.txavail = di->ntxd - NTXDACTIVE (di->txin, di->txout) - 1;
1753
1754  /* kick the chip */
1755  W_REG (di->osh, &di->d32txregs->ptr, I2B (di->txout, dma32dd_t));
1756}
1757
1758/* 64 bits DMA functions */
1759
1760#ifdef BCMDMA64
1761static void
1762dma64_txinit (dma_info_t * di)
1763{
1764  DMA_TRACE (("%s: dma_txinit\n", di->name));
1765
1766  if (di->ntxd == 0)
1767    return;
1768
1769  di->txin = di->txout = 0;
1770  di->hnddma.txavail = di->ntxd - 1;
1771
1772  /* clear tx descriptor ring */
1773  BZERO_SM ((void *) (uintptr) di->txd64, (di->ntxd * sizeof (dma64dd_t)));
1774  W_REG (di->osh, &di->d64txregs->control, D64_XC_XE);
1775  _dma_ddtable_init (di, DMA_TX, di->txdpa);
1776}
1777
1778static bool
1779dma64_txenabled (dma_info_t * di)
1780{
1781  uint32 xc;
1782
1783  /* If the chip is dead, it is not enabled :-) */
1784  xc = R_REG (di->osh, &di->d64txregs->control);
1785  return ((xc != 0xffffffff) && (xc & D64_XC_XE));
1786}
1787
1788static void
1789dma64_txsuspend (dma_info_t * di)
1790{
1791  DMA_TRACE (("%s: dma_txsuspend\n", di->name));
1792
1793  if (di->ntxd == 0)
1794    return;
1795
1796  OR_REG (di->osh, &di->d64txregs->control, D64_XC_SE);
1797}
1798
1799static void
1800dma64_txresume (dma_info_t * di)
1801{
1802  DMA_TRACE (("%s: dma_txresume\n", di->name));
1803
1804  if (di->ntxd == 0)
1805    return;
1806
1807  AND_REG (di->osh, &di->d64txregs->control, ~D64_XC_SE);
1808}
1809
1810static bool
1811dma64_txsuspended (dma_info_t * di)
1812{
1813  return (di->ntxd == 0)
1814    || ((R_REG (di->osh, &di->d64txregs->control) & D64_XC_SE) == D64_XC_SE);
1815}
1816
1817static void
1818dma64_txreclaim (dma_info_t * di, bool forceall)
1819{
1820  void *p;
1821
1822  DMA_TRACE (("%s: dma_txreclaim %s\n", di->name, forceall ? "all" : ""));
1823
1824  while ((p = dma64_getnexttxp (di, forceall)))
1825    PKTFREE (di->osh, p, TRUE);
1826}
1827
1828static bool
1829dma64_txstopped (dma_info_t * di)
1830{
1831  return ((R_REG (di->osh, &di->d64txregs->status0) & D64_XS0_XS_MASK) ==
1832      D64_XS0_XS_STOPPED);
1833}
1834
1835static bool
1836dma64_rxstopped (dma_info_t * di)
1837{
1838  return ((R_REG (di->osh, &di->d64rxregs->status0) & D64_RS0_RS_MASK) ==
1839      D64_RS0_RS_STOPPED);
1840}
1841
1842static bool
1843dma64_alloc (dma_info_t * di, uint direction)
1844{
1845  uint size;
1846  uint ddlen;
1847  uint32 alignbytes;
1848  void *va;
1849
1850  ddlen = sizeof (dma64dd_t);
1851
1852  size = (direction == DMA_TX) ? (di->ntxd * ddlen) : (di->nrxd * ddlen);
1853
1854  alignbytes = di->dma64align;
1855
1856  if (!ISALIGNED (DMA_CONSISTENT_ALIGN, alignbytes))
1857    size += alignbytes;
1858
1859  if (direction == DMA_TX)
1860    {
1861      if ((va =
1862       DMA_ALLOC_CONSISTENT (di->osh, size, &di->txdpa,
1863                 &di->tx_dmah)) == NULL)
1864    {
1865      DMA_ERROR (("%s: dma_attach: DMA_ALLOC_CONSISTENT(ntxd) failed\n",
1866              di->name));
1867      return FALSE;
1868    }
1869
1870      di->txd64 = (dma64dd_t *) ROUNDUP ((uintptr) va, alignbytes);
1871      di->txdalign = (uint) ((int8 *) (uintptr) di->txd64 - (int8 *) va);
1872      di->txdpa += di->txdalign;
1873      di->txdalloc = size;
1874      ASSERT (ISALIGNED ((uintptr) di->txd64, alignbytes));
1875    }
1876  else
1877    {
1878      if ((va =
1879       DMA_ALLOC_CONSISTENT (di->osh, size, &di->rxdpa,
1880                 &di->rx_dmah)) == NULL)
1881    {
1882      DMA_ERROR (("%s: dma_attach: DMA_ALLOC_CONSISTENT(nrxd) failed\n",
1883              di->name));
1884      return FALSE;
1885    }
1886      di->rxd64 = (dma64dd_t *) ROUNDUP ((uintptr) va, alignbytes);
1887      di->rxdalign = (uint) ((int8 *) (uintptr) di->rxd64 - (int8 *) va);
1888      di->rxdpa += di->rxdalign;
1889      di->rxdalloc = size;
1890      ASSERT (ISALIGNED ((uintptr) di->rxd64, alignbytes));
1891    }
1892
1893  return TRUE;
1894}
1895
1896static bool
1897dma64_txreset (dma_info_t * di)
1898{
1899  uint32 status;
1900
1901  if (di->ntxd == 0)
1902    return TRUE;
1903
1904  /* suspend tx DMA first */
1905  W_REG (di->osh, &di->d64txregs->control, D64_XC_SE);
1906  SPINWAIT (((status =
1907          (R_REG (di->osh, &di->d64txregs->status0) & D64_XS0_XS_MASK)) !=
1908         D64_XS0_XS_DISABLED) && (status != D64_XS0_XS_IDLE)
1909        && (status != D64_XS0_XS_STOPPED), 10000);
1910
1911  W_REG (di->osh, &di->d64txregs->control, 0);
1912  SPINWAIT (((status =
1913          (R_REG (di->osh, &di->d64txregs->status0) & D64_XS0_XS_MASK)) !=
1914         D64_XS0_XS_DISABLED), 10000);
1915
1916  /* wait for the last transaction to complete */
1917  OSL_DELAY (300);
1918
1919  return (status == D64_XS0_XS_DISABLED);
1920}
1921
1922static bool
1923dma64_rxidle (dma_info_t * di)
1924{
1925  DMA_TRACE (("%s: dma_rxidle\n", di->name));
1926
1927  if (di->nrxd == 0)
1928    return TRUE;
1929
1930  return ((R_REG (di->osh, &di->d64rxregs->status0) & D64_RS0_CD_MASK) ==
1931      R_REG (di->osh, &di->d64rxregs->ptr));
1932}
1933
1934static bool
1935dma64_rxreset (dma_info_t * di)
1936{
1937  uint32 status;
1938
1939  if (di->nrxd == 0)
1940    return TRUE;
1941
1942  W_REG (di->osh, &di->d64rxregs->control, 0);
1943  SPINWAIT (((status =
1944          (R_REG (di->osh, &di->d64rxregs->status0) & D64_RS0_RS_MASK)) !=
1945         D64_RS0_RS_DISABLED), 10000);
1946
1947  return (status == D64_RS0_RS_DISABLED);
1948}
1949
1950static bool
1951dma64_rxenabled (dma_info_t * di)
1952{
1953  uint32 rc;
1954
1955  rc = R_REG (di->osh, &di->d64rxregs->control);
1956  return ((rc != 0xffffffff) && (rc & D64_RC_RE));
1957}
1958
1959static bool
1960dma64_txsuspendedidle (dma_info_t * di)
1961{
1962
1963  if (di->ntxd == 0)
1964    return TRUE;
1965
1966  if (!(R_REG (di->osh, &di->d64txregs->control) & D64_XC_SE))
1967    return 0;
1968
1969  if ((R_REG (di->osh, &di->d64txregs->status0) & D64_XS0_XS_MASK) ==
1970      D64_XS0_XS_IDLE)
1971    return 1;
1972
1973  return 0;
1974}
1975
1976
1977/* !! tx entry routine */
1978static int
1979dma64_txfast (dma_info_t * di, void *p0, bool commit)
1980{
1981  void *p, *next;
1982  uchar *data;
1983  uint len;
1984  uint txout;
1985  uint32 flags = 0;
1986  uint32 pa;
1987
1988  DMA_TRACE (("%s: dma_txfast\n", di->name));
1989
1990  txout = di->txout;
1991
1992  /*
1993   * Walk the chain of packet buffers
1994   * allocating and initializing transmit descriptor entries.
1995   */
1996  for (p = p0; p; p = next)
1997    {
1998      data = PKTDATA (di->osh, p);
1999      len = PKTLEN (di->osh, p);
2000      next = PKTNEXT (di->osh, p);
2001
2002      /* return nonzero if out of tx descriptors */
2003      if (NEXTTXD (txout) == di->txin)
2004    goto outoftxd;
2005
2006      if (len == 0)
2007    continue;
2008
2009      /* get physical address of buffer start */
2010      pa =
2011    (uint32) DMA_MAP (di->osh, data, len, DMA_TX, p,
2012              &di->txp_dmah[txout]);
2013
2014      flags = 0;
2015      if (p == p0)
2016    flags |= D64_CTRL1_SOF;
2017      if (next == NULL)
2018    flags |= (D64_CTRL1_IOC | D64_CTRL1_EOF);
2019      if (txout == (di->ntxd - 1))
2020    flags |= D64_CTRL1_EOT;
2021
2022      dma64_dd_upd (di, di->txd64, pa, txout, &flags, len);
2023      ASSERT (di->txp[txout] == NULL);
2024
2025      txout = NEXTTXD (txout);
2026    }
2027
2028  /* if last txd eof not set, fix it */
2029  if (!(flags & D64_CTRL1_EOF))
2030    W_SM (&di->txd64[PREVTXD (txout)].ctrl1,
2031      BUS_SWAP32 (flags | D64_CTRL1_IOC | D64_CTRL1_EOF));
2032
2033  /* save the packet */
2034  di->txp[PREVTXD (txout)] = p0;
2035
2036  /* bump the tx descriptor index */
2037  di->txout = txout;
2038
2039  /* kick the chip */
2040  if (commit)
2041    W_REG (di->osh, &di->d64txregs->ptr, I2B (txout, dma64dd_t));
2042
2043  /* tx flow control */
2044  di->hnddma.txavail = di->ntxd - NTXDACTIVE (di->txin, di->txout) - 1;
2045
2046  return (0);
2047
2048outoftxd:
2049  DMA_ERROR (("%s: dma_txfast: out of txds\n", di->name));
2050  PKTFREE (di->osh, p0, TRUE);
2051  di->hnddma.txavail = 0;
2052  di->hnddma.txnobuf++;
2053  return (-1);
2054}
2055
2056/*
2057 * Reclaim next completed txd (txds if using chained buffers) and
2058 * return associated packet.
2059 * If 'force' is true, reclaim txd(s) and return associated packet
2060 * regardless of the value of the hardware "curr" pointer.
2061 */
2062static void *
2063dma64_getnexttxp (dma_info_t * di, bool forceall)
2064{
2065  uint start, end, i;
2066  void *txp;
2067
2068  DMA_TRACE (("%s: dma_getnexttxp %s\n", di->name, forceall ? "all" : ""));
2069
2070  if (di->ntxd == 0)
2071    return (NULL);
2072
2073  txp = NULL;
2074
2075  start = di->txin;
2076  if (forceall)
2077    end = di->txout;
2078  else
2079    end =
2080      B2I (R_REG (di->osh, &di->d64txregs->status0) & D64_XS0_CD_MASK,
2081       dma64dd_t);
2082
2083  if ((start == 0) && (end > di->txout))
2084    goto bogus;
2085
2086  for (i = start; i != end && !txp; i = NEXTTXD (i))
2087    {
2088      DMA_UNMAP (di->osh,
2089         (BUS_SWAP32 (R_SM (&di->txd64[i].addrlow)) -
2090          di->dataoffsetlow),
2091         (BUS_SWAP32 (R_SM (&di->txd64[i].ctrl2)) &
2092          D64_CTRL2_BC_MASK), DMA_TX, di->txp[i], &di->txp_dmah[i]);
2093
2094      W_SM (&di->txd64[i].addrlow, 0xdeadbeef);
2095      W_SM (&di->txd64[i].addrhigh, 0xdeadbeef);
2096
2097      txp = di->txp[i];
2098      di->txp[i] = NULL;
2099    }
2100
2101  di->txin = i;
2102
2103  /* tx flow control */
2104  di->hnddma.txavail = di->ntxd - NTXDACTIVE (di->txin, di->txout) - 1;
2105
2106  return (txp);
2107
2108bogus:
2109/*
2110    DMA_ERROR(("dma_getnexttxp: bogus curr: start %d end %d txout %d force %d\n",
2111        start, end, di->txout, forceall));
2112*/
2113  return (NULL);
2114}
2115
2116static void *
2117dma64_getnextrxp (dma_info_t * di, bool forceall)
2118{
2119  uint i;
2120  void *rxp;
2121
2122  /* if forcing, dma engine must be disabled */
2123  ASSERT (!forceall || !dma64_rxenabled (di));
2124
2125  i = di->rxin;
2126
2127  /* return if no packets posted */
2128  if (i == di->rxout)
2129    return (NULL);
2130
2131  /* ignore curr if forceall */
2132  if (!forceall &&
2133      (i ==
2134       B2I (R_REG (di->osh, &di->d64rxregs->status0) & D64_RS0_CD_MASK,
2135        dma64dd_t)))
2136    return (NULL);
2137
2138  /* get the packet pointer that corresponds to the rx descriptor */
2139  rxp = di->rxp[i];
2140  ASSERT (rxp);
2141  di->rxp[i] = NULL;
2142
2143  /* clear this packet from the descriptor ring */
2144  DMA_UNMAP (di->osh,
2145         (BUS_SWAP32 (R_SM (&di->rxd64[i].addrlow)) - di->dataoffsetlow),
2146         di->rxbufsize, DMA_RX, rxp, &di->rxp_dmah[i]);
2147
2148  W_SM (&di->rxd64[i].addrlow, 0xdeadbeef);
2149  W_SM (&di->rxd64[i].addrhigh, 0xdeadbeef);
2150
2151  di->rxin = NEXTRXD (i);
2152
2153  return (rxp);
2154}
2155
2156static bool
2157_dma64_addrext (osl_t * osh, dma64regs_t * dma64regs)
2158{
2159  uint32 w;
2160  OR_REG (osh, &dma64regs->control, D64_XC_AE);
2161  w = R_REG (osh, &dma64regs->control);
2162  AND_REG (osh, &dma64regs->control, ~D64_XC_AE);
2163  return ((w & D64_XC_AE) == D64_XC_AE);
2164}
2165
2166/*
2167 * Rotate all active tx dma ring entries "forward" by (ActiveDescriptor - txin).
2168 */
2169static void
2170dma64_txrotate (dma_info_t * di)
2171{
2172  uint ad;
2173  uint nactive;
2174  uint rot;
2175  uint old, new;
2176  uint32 w;
2177  uint first, last;
2178
2179  ASSERT (dma64_txsuspendedidle (di));
2180
2181  nactive = _dma_txactive (di);
2182  ad =
2183    B2I ((R_REG (di->osh, &di->d64txregs->status1) & D64_XS1_AD_MASK),
2184     dma64dd_t);
2185  rot = TXD (ad - di->txin);
2186
2187  ASSERT (rot < di->ntxd);
2188
2189  /* full-ring case is a lot harder - don't worry about this */
2190  if (rot >= (di->ntxd - nactive))
2191    {
2192      DMA_ERROR (("%s: dma_txrotate: ring full - punt\n", di->name));
2193      return;
2194    }
2195
2196  first = di->txin;
2197  last = PREVTXD (di->txout);
2198
2199  /* move entries starting at last and moving backwards to first */
2200  for (old = last; old != PREVTXD (first); old = PREVTXD (old))
2201    {
2202      new = TXD (old + rot);
2203
2204      /*
2205       * Move the tx dma descriptor.
2206       * EOT is set only in the last entry in the ring.
2207       */
2208      w = BUS_SWAP32 (R_SM (&di->txd64[old].ctrl1)) & ~D64_CTRL1_EOT;
2209      if (new == (di->ntxd - 1))
2210    w |= D64_CTRL1_EOT;
2211      W_SM (&di->txd64[new].ctrl1, BUS_SWAP32 (w));
2212
2213      w = BUS_SWAP32 (R_SM (&di->txd64[old].ctrl2));
2214      W_SM (&di->txd64[new].ctrl2, BUS_SWAP32 (w));
2215
2216      W_SM (&di->txd64[new].addrlow, R_SM (&di->txd64[old].addrlow));
2217      W_SM (&di->txd64[new].addrhigh, R_SM (&di->txd64[old].addrhigh));
2218
2219      /* zap the old tx dma descriptor address field */
2220      W_SM (&di->txd64[old].addrlow, BUS_SWAP32 (0xdeadbeef));
2221      W_SM (&di->txd64[old].addrhigh, BUS_SWAP32 (0xdeadbeef));
2222
2223      /* move the corresponding txp[] entry */
2224      ASSERT (di->txp[new] == NULL);
2225      di->txp[new] = di->txp[old];
2226      di->txp[old] = NULL;
2227    }
2228
2229  /* update txin and txout */
2230  di->txin = ad;
2231  di->txout = TXD (di->txout + rot);
2232  di->hnddma.txavail = di->ntxd - NTXDACTIVE (di->txin, di->txout) - 1;
2233
2234  /* kick the chip */
2235  W_REG (di->osh, &di->d64txregs->ptr, I2B (di->txout, dma64dd_t));
2236}
2237
2238#endif /* BCMDMA64 */
2239
2240uint
2241dma_addrwidth (sb_t * sbh, void *dmaregs)
2242{
2243  dma32regs_t *dma32regs;
2244  osl_t *osh;
2245
2246  osh = sb_osh (sbh);
2247
2248  if (DMA64_CAP)
2249    {
2250      /* DMA engine is 64-bit capable */
2251      if (((sb_coreflagshi (sbh, 0, 0) & SBTMH_DMA64) == SBTMH_DMA64))
2252    {
2253      /* backplane are 64 bits capable */
2254      if (sb_backplane64 (sbh))
2255        /* If bus is System Backplane or PCIE then we can access 64-bits */
2256        if ((BUSTYPE (sbh->bustype) == SB_BUS) ||
2257        ((BUSTYPE (sbh->bustype) == PCI_BUS) &&
2258         sbh->buscoretype == SB_PCIE))
2259          return (DMADDRWIDTH_64);
2260
2261      /* DMA64 is always 32 bits capable, AE is always TRUE */
2262#ifdef BCMDMA64
2263      ASSERT (_dma64_addrext (osh, (dma64regs_t *) dmaregs));
2264#endif
2265      return (DMADDRWIDTH_32);
2266    }
2267    }
2268
2269  /* Start checking for 32-bit / 30-bit addressing */
2270  dma32regs = (dma32regs_t *) dmaregs;
2271
2272  /* For System Backplane, PCIE bus or addrext feature, 32-bits ok */
2273  if ((BUSTYPE (sbh->bustype) == SB_BUS) ||
2274      ((BUSTYPE (sbh->bustype) == PCI_BUS) && sbh->buscoretype == SB_PCIE) ||
2275      (_dma32_addrext (osh, dma32regs)))
2276    return (DMADDRWIDTH_32);
2277
2278  /* Fallthru */
2279  return (DMADDRWIDTH_30);
2280}
package/broadcom-wl-old/src/driver/hnddma.h
1/*
2 * Generic Broadcom Home Networking Division (HND) DMA engine SW interface
3 * This supports the following chips: BCM42xx, 44xx, 47xx .
4 *
5 * Copyright 2007, Broadcom Corporation
6 * All Rights Reserved.
7 *
8 * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
9 * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
10 * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
11 * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
12 */
13
14#ifndef _hnddma_h_
15#define _hnddma_h_
16
17typedef const struct hnddma_pub hnddma_t;
18
19/* dma function type */
20typedef void (*di_detach_t)(hnddma_t *dmah);
21typedef bool (*di_txreset_t)(hnddma_t *dmah);
22typedef bool (*di_rxreset_t)(hnddma_t *dmah);
23typedef bool (*di_rxidle_t)(hnddma_t *dmah);
24typedef void (*di_txinit_t)(hnddma_t *dmah);
25typedef bool (*di_txenabled_t)(hnddma_t *dmah);
26typedef void (*di_rxinit_t)(hnddma_t *dmah);
27typedef void (*di_txsuspend_t)(hnddma_t *dmah);
28typedef void (*di_txresume_t)(hnddma_t *dmah);
29typedef bool (*di_txsuspended_t)(hnddma_t *dmah);
30typedef bool (*di_txsuspendedidle_t)(hnddma_t *dmah);
31typedef int (*di_txfast_t)(hnddma_t *dmah, void *p, bool commit);
32typedef void (*di_fifoloopbackenable_t)(hnddma_t *dmah);
33typedef bool (*di_txstopped_t)(hnddma_t *dmah);
34typedef bool (*di_rxstopped_t)(hnddma_t *dmah);
35typedef bool (*di_rxenable_t)(hnddma_t *dmah);
36typedef bool (*di_rxenabled_t)(hnddma_t *dmah);
37typedef void* (*di_rx_t)(hnddma_t *dmah);
38typedef void (*di_rxfill_t)(hnddma_t *dmah);
39typedef void (*di_txreclaim_t)(hnddma_t *dmah, bool forceall);
40typedef void (*di_rxreclaim_t)(hnddma_t *dmah);
41typedef uintptr (*di_getvar_t)(hnddma_t *dmah, const char *name);
42typedef void* (*di_getnexttxp_t)(hnddma_t *dmah, bool forceall);
43typedef void* (*di_getnextrxp_t)(hnddma_t *dmah, bool forceall);
44typedef void* (*di_peeknexttxp_t)(hnddma_t *dmah);
45typedef void (*di_txblock_t)(hnddma_t *dmah);
46typedef void (*di_txunblock_t)(hnddma_t *dmah);
47typedef uint (*di_txactive_t)(hnddma_t *dmah);
48typedef void (*di_txrotate_t)(hnddma_t *dmah);
49typedef void (*di_counterreset_t)(hnddma_t *dmah);
50typedef char* (*di_dump_t)(hnddma_t *dmah, struct bcmstrbuf *b, bool dumpring);
51typedef char* (*di_dumptx_t)(hnddma_t *dmah, struct bcmstrbuf *b, bool dumpring);
52typedef char* (*di_dumprx_t)(hnddma_t *dmah, struct bcmstrbuf *b, bool dumpring);
53
54/* dma opsvec */
55typedef struct di_fcn_s {
56    di_detach_t detach;
57    di_txinit_t txinit;
58    di_txreset_t txreset;
59    di_txenabled_t txenabled;
60    di_txsuspend_t txsuspend;
61    di_txresume_t txresume;
62    di_txsuspended_t txsuspended;
63    di_txsuspendedidle_t txsuspendedidle;
64    di_txfast_t txfast;
65    di_txstopped_t txstopped;
66    di_txreclaim_t txreclaim;
67    di_getnexttxp_t getnexttxp;
68    di_peeknexttxp_t peeknexttxp;
69    di_txblock_t txblock;
70    di_txunblock_t txunblock;
71    di_txactive_t txactive;
72    di_txrotate_t txrotate;
73
74    di_rxinit_t rxinit;
75    di_rxreset_t rxreset;
76    di_rxidle_t rxidle;
77    di_rxstopped_t rxstopped;
78    di_rxenable_t rxenable;
79    di_rxenabled_t rxenabled;
80    di_rx_t rx;
81    di_rxfill_t rxfill;
82    di_rxreclaim_t rxreclaim;
83    di_getnextrxp_t getnextrxp;
84
85    di_fifoloopbackenable_t fifoloopbackenable;
86    di_getvar_t d_getvar;
87    di_counterreset_t counterreset;
88    di_dump_t dump;
89    di_dumptx_t dumptx;
90    di_dumprx_t dumprx;
91    uint endnum;
92} di_fcn_t;
93
94/*
95 * Exported data structure (read-only)
96 */
97/* export structure */
98struct hnddma_pub {
99    di_fcn_t di_fn; /* DMA function pointers */
100    uint txavail; /* # free tx descriptors */
101
102    /* rx error counters */
103    uint rxgiants; /* rx giant frames */
104    uint rxnobuf; /* rx out of dma descriptors */
105    /* tx error counters */
106    uint txnobuf; /* tx out of dma descriptors */
107};
108
109
110extern hnddma_t * dma_attach(osl_t *osh, char *name, sb_t *sbh, void *dmaregstx, void *dmaregsrx,
111                             uint ntxd, uint nrxd, uint rxbufsize, uint nrxpost, uint rxoffset,
112                             uint *msg_level);
113#define dma_detach(di) ((di)->di_fn.detach(di))
114#define dma_txreset(di) ((di)->di_fn.txreset(di))
115#define dma_rxreset(di) ((di)->di_fn.rxreset(di))
116#define dma_rxidle(di) ((di)->di_fn.rxidle(di))
117#define dma_txinit(di) ((di)->di_fn.txinit(di))
118#define dma_txenabled(di) ((di)->di_fn.txenabled(di))
119#define dma_rxinit(di) ((di)->di_fn.rxinit(di))
120#define dma_txsuspend(di) ((di)->di_fn.txsuspend(di))
121#define dma_txresume(di) ((di)->di_fn.txresume(di))
122#define dma_txsuspended(di) ((di)->di_fn.txsuspended(di))
123#define dma_txsuspendedidle(di) ((di)->di_fn.txsuspendedidle(di))
124#define dma_txfast(di, p, commit) ((di)->di_fn.txfast(di, p, commit))
125#define dma_fifoloopbackenable(di) ((di)->di_fn.fifoloopbackenable(di))
126#define dma_txstopped(di) ((di)->di_fn.txstopped(di))
127#define dma_rxstopped(di) ((di)->di_fn.rxstopped(di))
128#define dma_rxenable(di) ((di)->di_fn.rxenable(di))
129#define dma_rxenabled(di) ((di)->di_fn.rxenabled(di))
130#define dma_rx(di) ((di)->di_fn.rx(di))
131#define dma_rxfill(di) ((di)->di_fn.rxfill(di))
132#define dma_txreclaim(di, forceall) ((di)->di_fn.txreclaim(di, forceall))
133#define dma_rxreclaim(di) ((di)->di_fn.rxreclaim(di))
134#define dma_getvar(di, name) ((di)->di_fn.d_getvar(di, name))
135#define dma_getnexttxp(di, forceall) ((di)->di_fn.getnexttxp(di, forceall))
136#define dma_getnextrxp(di, forceall) ((di)->di_fn.getnextrxp(di, forceall))
137#define dma_peeknexttxp(di) ((di)->di_fn.peeknexttxp(di))
138#define dma_txblock(di) ((di)->di_fn.txblock(di))
139#define dma_txunblock(di) ((di)->di_fn.txunblock(di))
140#define dma_txactive(di) ((di)->di_fn.txactive(di))
141#define dma_txrotate(di) ((di)->di_fn.txrotate(di))
142#define dma_counterreset(di) ((di)->di_fn.counterreset(di))
143#ifdef BCMDBG
144#define dma_dump(di, buf, dumpring) ((di)->di_fn.dump(di, buf, dumpring))
145#define dma_dumptx(di, buf, dumpring) ((di)->di_fn.dumptx(di, buf, dumpring))
146#define dma_dumprx(di, buf, dumpring) ((di)->di_fn.dumprx(di, buf, dumpring))
147#endif
148
149/* return addresswidth allowed
150 * This needs to be done after SB attach but before dma attach.
151 * SB attach provides ability to probe backplane and dma core capabilities
152 * This info is needed by DMA_ALLOC_CONSISTENT in dma attach
153 */
154extern uint dma_addrwidth(sb_t *sbh, void *dmaregs);
155
156/* pio helpers */
157void dma_txpioloopback(osl_t *osh, dma32regs_t *);
158
159#endif /* _hnddma_h_ */
</
package/broadcom-wl-old/src/driver/linux_osl.c
1/*
2 * Linux OS Independent Layer
3 *
4 * Copyright 2007, Broadcom Corporation
5 * All Rights Reserved.
6 *
7 * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
8 * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
9 * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
10 * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
11 *
12 */
13
14#define LINUX_OSL
15
16#include <typedefs.h>
17#include <bcmendian.h>
18#include <linuxver.h>
19#include <bcmdefs.h>
20#include <osl.h>
21#include "linux_osl.h"
22#include "bcmutils.h"
23#include <linux/delay.h>
24#ifdef mips
25#include <asm/paccess.h>
26#endif /* mips */
27#include <pcicfg.h>
28
29#define PCI_CFG_RETRY 10
30
31#define OS_HANDLE_MAGIC 0x1234abcd /* Magic # to recognise osh */
32#define BCM_MEM_FILENAME_LEN 24 /* Mem. filename length */
33
34typedef struct bcm_mem_link
35{
36  struct bcm_mem_link *prev;
37  struct bcm_mem_link *next;
38  uint size;
39  int line;
40  char file[BCM_MEM_FILENAME_LEN];
41} bcm_mem_link_t;
42
43#if 0
44struct osl_info
45{
46  osl_pubinfo_t pub;
47  uint magic;
48  void *pdev;
49  uint malloced;
50  uint failed;
51  uint bustype;
52  bcm_mem_link_t *dbgmem_list;
53#ifdef BCMDBG_PKT /* pkt logging for debugging */
54  pktlist_info_t pktlist;
55#endif /* BCMDBG_PKT */
56};
57#endif
58
59static int16 linuxbcmerrormap[] = { 0, /* 0 */
60  -EINVAL, /* BCME_ERROR */
61  -EINVAL, /* BCME_BADARG */
62  -EINVAL, /* BCME_BADOPTION */
63  -EINVAL, /* BCME_NOTUP */
64  -EINVAL, /* BCME_NOTDOWN */
65  -EINVAL, /* BCME_NOTAP */
66  -EINVAL, /* BCME_NOTSTA */
67  -EINVAL, /* BCME_BADKEYIDX */
68  -EINVAL, /* BCME_RADIOOFF */
69  -EINVAL, /* BCME_NOTBANDLOCKED */
70  -EINVAL, /* BCME_NOCLK */
71  -EINVAL, /* BCME_BADRATESET */
72  -EINVAL, /* BCME_BADBAND */
73  -E2BIG, /* BCME_BUFTOOSHORT */
74  -E2BIG, /* BCME_BUFTOOLONG */
75  -EBUSY, /* BCME_BUSY */
76  -EINVAL, /* BCME_NOTASSOCIATED */
77  -EINVAL, /* BCME_BADSSIDLEN */
78  -EINVAL, /* BCME_OUTOFRANGECHAN */
79  -EINVAL, /* BCME_BADCHAN */
80  -EFAULT, /* BCME_BADADDR */
81  -ENOMEM, /* BCME_NORESOURCE */
82  -EOPNOTSUPP, /* BCME_UNSUPPORTED */
83  -EMSGSIZE, /* BCME_BADLENGTH */
84  -EINVAL, /* BCME_NOTREADY */
85  -EPERM, /* BCME_NOTPERMITTED */
86  -ENOMEM, /* BCME_NOMEM */
87  -EINVAL, /* BCME_ASSOCIATED */
88  -ERANGE, /* BCME_RANGE */
89  -EINVAL, /* BCME_NOTFOUND */
90  -EINVAL, /* BCME_WME_NOT_ENABLED */
91  -EINVAL, /* BCME_TSPEC_NOTFOUND */
92  -EINVAL, /* BCME_ACM_NOTSUPPORTED */
93  -EINVAL, /* BCME_NOT_WME_ASSOCIATION */
94  -EIO, /* BCME_SDIO_ERROR */
95  -ENODEV, /* BCME_DONGLE_DOWN */
96  -EINVAL /* BCME_VERSION */
97/* When an new error code is added to bcmutils.h, add os
98 * spcecific error translation here as well
99 */
100/* check if BCME_LAST changed since the last time this function was updated */
101#if BCME_LAST != -37
102#error "You need to add a OS error translation in the linuxbcmerrormap \
103    for new error code defined in bcmuitls.h"
104#endif /* BCME_LAST != -37 */
105};
106
107/* translate bcmerrors into linux errors */
108int
109osl_error (int bcmerror)
110{
111  if (bcmerror > 0)
112    bcmerror = 0;
113  else if (bcmerror < BCME_LAST)
114    bcmerror = BCME_ERROR;
115
116  /* Array bounds covered by ASSERT in osl_attach */
117  return linuxbcmerrormap[-bcmerror];
118}
119
120osl_t *
121osl_attach (void *pdev, uint bustype, bool pkttag)
122{
123  osl_t *osh;
124
125  osh = kmalloc (sizeof (osl_t), GFP_ATOMIC);
126  ASSERT (osh);
127
128  bzero (osh, sizeof (osl_t));
129
130  /* Check that error map has the right number of entries in it */
131  ASSERT (ABS (BCME_LAST) == (ARRAYSIZE (linuxbcmerrormap) - 1));
132
133  osh->magic = OS_HANDLE_MAGIC;
134  osh->malloced = 0;
135  osh->failed = 0;
136  osh->dbgmem_list = NULL;
137  osh->pdev = pdev;
138  osh->pub.pkttag = pkttag;
139  osh->bustype = bustype;
140
141  switch (bustype)
142    {
143    case PCI_BUS:
144    case SB_BUS:
145    case PCMCIA_BUS:
146      osh->pub.mmbus = TRUE;
147      break;
148    case JTAG_BUS:
149    case SDIO_BUS:
150      break;
151    default:
152      ASSERT (FALSE);
153      break;
154    }
155
156#ifdef BCMDBG
157  if (pkttag)
158    {
159      struct sk_buff *skb;
160      ASSERT (OSL_PKTTAG_SZ <= sizeof (skb->cb));
161    }
162#endif
163  return osh;
164}
165
166void
167osl_detach (osl_t * osh)
168{
169  if (osh == NULL)
170    return;
171
172  ASSERT (osh->magic == OS_HANDLE_MAGIC);
173  kfree (osh);
174}
175
176/* Return a new packet. zero out pkttag */
177void *
178osl_pktget (osl_t * osh, uint len)
179{
180  struct sk_buff *skb;
181
182  if ((skb = dev_alloc_skb (len)))
183    {
184      skb_put (skb, len);
185      skb->priority = 0;
186
187#ifdef BCMDBG_PKT
188      pktlist_add (&(osh->pktlist), (void *) skb);
189#endif /* BCMDBG_PKT */
190
191      osh->pub.pktalloced++;
192    }
193
194  return ((void *) skb);
195}
196
197/* Free the driver packet. Free the tag if present */
198void
199osl_pktfree (osl_t * osh, void *p, bool send)
200{
201  struct sk_buff *skb, *nskb;
202
203  skb = (struct sk_buff *) p;
204
205  if (send && osh->pub.tx_fn)
206    osh->pub.tx_fn (osh->pub.tx_ctx, p, 0);
207
208  /* perversion: we use skb->next to chain multi-skb packets */
209  while (skb)
210    {
211      nskb = skb->next;
212      skb->next = NULL;
213
214#ifdef BCMDBG_PKT
215      pktlist_remove (&(osh->pktlist), (void *) skb);
216#endif /* BCMDBG_PKT */
217
218      if (skb->destructor)
219    {
220      /* cannot kfree_skb() on hard IRQ (net/core/skbuff.c) if destructor exists
221       */
222      dev_kfree_skb_any (skb);
223    }
224      else
225    {
226      /* can free immediately (even in_irq()) if destructor does not exist */
227      dev_kfree_skb (skb);
228    }
229
230      osh->pub.pktalloced--;
231
232      skb = nskb;
233    }
234}
235
236uint32
237osl_pci_read_config (osl_t * osh, uint offset, uint size)
238{
239  uint val;
240  uint retry = PCI_CFG_RETRY;
241
242  ASSERT ((osh && (osh->magic == OS_HANDLE_MAGIC)));
243
244  /* only 4byte access supported */
245  ASSERT (size == 4);
246
247  do
248    {
249      pci_read_config_dword (osh->pdev, offset, &val);
250      if (val != 0xffffffff)
251    break;
252    }
253  while (retry--);
254
255#ifdef BCMDBG
256  if (retry < PCI_CFG_RETRY)
257    printk ("PCI CONFIG READ access to %d required %d retries\n", offset,
258        (PCI_CFG_RETRY - retry));
259#endif /* BCMDBG */
260
261  return (val);
262}
263
264void
265osl_pci_write_config (osl_t * osh, uint offset, uint size, uint val)
266{
267  uint retry = PCI_CFG_RETRY;
268
269  ASSERT ((osh && (osh->magic == OS_HANDLE_MAGIC)));
270
271  /* only 4byte access supported */
272  ASSERT (size == 4);
273
274  do
275    {
276      pci_write_config_dword (osh->pdev, offset, val);
277      if (offset != PCI_BAR0_WIN)
278    break;
279      if (osl_pci_read_config (osh, offset, size) == val)
280    break;
281    }
282  while (retry--);
283
284#ifdef BCMDBG
285  if (retry < PCI_CFG_RETRY)
286    printk ("PCI CONFIG WRITE access to %d required %d retries\n", offset,
287        (PCI_CFG_RETRY - retry));
288#endif /* BCMDBG */
289}
290
291/* return bus # for the pci device pointed by osh->pdev */
292uint
293osl_pci_bus (osl_t * osh)
294{
295  ASSERT (osh && (osh->magic == OS_HANDLE_MAGIC) && osh->pdev);
296
297  return ((struct pci_dev *) osh->pdev)->bus->number;
298}
299
300/* return slot # for the pci device pointed by osh->pdev */
301uint
302osl_pci_slot (osl_t * osh)
303{
304  ASSERT (osh && (osh->magic == OS_HANDLE_MAGIC) && osh->pdev);
305
306  return PCI_SLOT (((struct pci_dev *) osh->pdev)->devfn);
307}
308
309static void
310osl_pcmcia_attr (osl_t * osh, uint offset, char *buf, int size, bool write)
311{
312}
313
314void
315osl_pcmcia_read_attr (osl_t * osh, uint offset, void *buf, int size)
316{
317  osl_pcmcia_attr (osh, offset, (char *) buf, size, FALSE);
318}
319
320void
321osl_pcmcia_write_attr (osl_t * osh, uint offset, void *buf, int size)
322{
323  osl_pcmcia_attr (osh, offset, (char *) buf, size, TRUE);
324}
325
326
327#ifdef BCMDBG_MEM
328
329void *
330osl_debug_malloc (osl_t * osh, uint size, int line, char *file)
331{
332  bcm_mem_link_t *p;
333  char *basename;
334
335  ASSERT (size);
336
337  if ((p =
338       (bcm_mem_link_t *) osl_malloc (osh,
339                      sizeof (bcm_mem_link_t) + size)) ==
340      NULL)
341    return (NULL);
342
343  p->size = size;
344  p->line = line;
345
346  basename = strrchr (file, '/');
347  /* skip the '/' */
348  if (basename)
349    basename++;
350
351  if (!basename)
352    basename = file;
353
354  strncpy (p->file, basename, BCM_MEM_FILENAME_LEN);
355  p->file[BCM_MEM_FILENAME_LEN - 1] = '\0';
356
357  /* link this block */
358  p->prev = NULL;
359  p->next = osh->dbgmem_list;
360  if (p->next)
361    p->next->prev = p;
362  osh->dbgmem_list = p;
363
364  return p + 1;
365}
366
367void
368osl_debug_mfree (osl_t * osh, void *addr, uint size, int line, char *file)
369{
370  bcm_mem_link_t *p =
371    (bcm_mem_link_t *) ((int8 *) addr - sizeof (bcm_mem_link_t));
372
373  ASSERT ((osh && (osh->magic == OS_HANDLE_MAGIC)));
374
375  if (p->size == 0)
376    {
377      printk
378    ("osl_debug_mfree: double free on addr %p size %d at line %d file %s\n",
379     addr, size, line, file);
380      ASSERT (p->size);
381      return;
382    }
383
384  if (p->size != size)
385    {
386      printk
387    ("osl_debug_mfree: dealloc size %d does not match alloc size %d on addr %p"
388     " at line %d file %s\n", size, p->size, addr, line, file);
389      ASSERT (p->size == size);
390      return;
391    }
392
393  /* unlink this block */
394  if (p->prev)
395    p->prev->next = p->next;
396  if (p->next)
397    p->next->prev = p->prev;
398  if (osh->dbgmem_list == p)
399    osh->dbgmem_list = p->next;
400  p->next = p->prev = NULL;
401
402  osl_mfree (osh, p, size + sizeof (bcm_mem_link_t));
403}
404
405int
406osl_debug_memdump (osl_t * osh, struct bcmstrbuf *b)
407{
408  bcm_mem_link_t *p;
409
410  ASSERT ((osh && (osh->magic == OS_HANDLE_MAGIC)));
411
412  bcm_bprintf (b, " Address\tSize\tFile:line\n");
413  for (p = osh->dbgmem_list; p; p = p->next)
414    bcm_bprintf (b, "0x%08x\t%5d\t%s:%d\n",
415         (uintptr) p + sizeof (bcm_mem_link_t), p->size, p->file,
416         p->line);
417
418  return 0;
419}
420
421#endif /* BCMDBG_MEM */
422
423void *
424osl_malloc (osl_t * osh, uint size)
425{
426  void *addr;
427
428  /* only ASSERT if osh is defined */
429  if (osh)
430    ASSERT (osh->magic == OS_HANDLE_MAGIC);
431
432  if ((addr = kmalloc (size, GFP_ATOMIC)) == NULL)
433    {
434      if (osh)
435    osh->failed++;
436      return (NULL);
437    }
438  if (osh)
439    osh->malloced += size;
440
441  return (addr);
442}
443
444void
445osl_mfree (osl_t * osh, void *addr, uint size)
446{
447  if (osh)
448    {
449      ASSERT (osh->magic == OS_HANDLE_MAGIC);
450      osh->malloced -= size;
451    }
452  kfree (addr);
453}
454
455uint
456osl_malloced (osl_t * osh)
457{
458  ASSERT ((osh && (osh->magic == OS_HANDLE_MAGIC)));
459  return (osh->malloced);
460}
461
462uint
463osl_malloc_failed (osl_t * osh)
464{
465  ASSERT ((osh && (osh->magic == OS_HANDLE_MAGIC)));
466  return (osh->failed);
467}
468
469void *
470osl_dma_alloc_consistent (osl_t * osh, uint size, ulong * pap)
471{
472  ASSERT ((osh && (osh->magic == OS_HANDLE_MAGIC)));
473
474  return (pci_alloc_consistent (osh->pdev, size, (dma_addr_t *) pap));
475}
476
477void
478osl_dma_free_consistent (osl_t * osh, void *va, uint size, ulong pa)
479{
480  ASSERT ((osh && (osh->magic == OS_HANDLE_MAGIC)));
481
482  pci_free_consistent (osh->pdev, size, va, (dma_addr_t) pa);
483}
484
485uint
486osl_dma_map (osl_t * osh, void *va, uint size, int direction)
487{
488  int dir;
489
490  ASSERT ((osh && (osh->magic == OS_HANDLE_MAGIC)));
491  dir = (direction == DMA_TX) ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE;
492  return (pci_map_single (osh->pdev, va, size, dir));
493}
494
495void
496osl_dma_unmap (osl_t * osh, uint pa, uint size, int direction)
497{
498  int dir;
499
500  ASSERT ((osh && (osh->magic == OS_HANDLE_MAGIC)));
501  dir = (direction == DMA_TX) ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE;
502  pci_unmap_single (osh->pdev, (uint32) pa, size, dir);
503}
504
505#if defined(BINOSL) || defined(BCMDBG_ASSERT)
506void
507osl_assert (char *exp, char *file, int line)
508{
509  char tempbuf[255];
510
511  sprintf (tempbuf, "assertion \"%s\" failed: file \"%s\", line %d\n", exp,
512       file, line);
513  panic (tempbuf);
514}
515#endif /* BCMDBG_ASSERT || BINOSL */
516
517void
518osl_delay (uint usec)
519{
520  uint d;
521
522  while (usec > 0)
523    {
524      d = MIN (usec, 1000);
525      udelay (d);
526      usec -= d;
527    }
528}
529
530/* Clone a packet.
531 * The pkttag contents are NOT cloned.
532 */
533void *
534osl_pktdup (osl_t * osh, void *skb)
535{
536  void *p;
537
538  if ((p = skb_clone ((struct sk_buff *) skb, GFP_ATOMIC)) == NULL)
539    return NULL;
540
541  /* skb_clone copies skb->cb.. we don't want that */
542  if (osh->pub.pkttag)
543    bzero ((void *) ((struct sk_buff *) p)->cb, OSL_PKTTAG_SZ);
544
545  /* Increment the packet counter */
546  osh->pub.pktalloced++;
547#ifdef BCMDBG_PKT
548  pktlist_add (&(osh->pktlist), (void *) p);
549#endif /* BCMDBG_PKT */
550  return (p);
551}
552
553uint
554osl_pktalloced (osl_t * osh)
555{
556  return (osh->pub.pktalloced);
557}
558
559#ifdef BCMDBG_PKT
560char *
561osl_pktlist_dump (osl_t * osh, char *buf)
562{
563  pktlist_dump (&(osh->pktlist), buf);
564  return buf;
565}
566
567void
568osl_pktlist_add (osl_t * osh, void *p)
569{
570  pktlist_add (&(osh->pktlist), p);
571}
572
573void
574osl_pktlist_remove (osl_t * osh, void *p)
575{
576  pktlist_remove (&(osh->pktlist), p);
577}
578#endif /* BCMDBG_PKT */
579
580/*
581 * BINOSL selects the slightly slower function-call-based binary compatible osl.
582 */
583#ifdef BINOSL
584
585int
586osl_printf (const char *format, ...)
587{
588  va_list args;
589  char buf[1024];
590  int len;
591
592  /* sprintf into a local buffer because there *is* no "vprintk()".. */
593  va_start (args, format);
594  len = vsnprintf (buf, 1024, format, args);