Adopt <net/if_stats.h>.diff -r1.19 -r1.20 src/sys/dev/ic/bwfm.c
(thorpej)
--- src/sys/dev/ic/bwfm.c 2019/12/27 09:22:20 1.19
+++ src/sys/dev/ic/bwfm.c 2020/01/29 14:14:55 1.20
@@ -1,1513 +1,1513 @@ | @@ -1,1513 +1,1513 @@ | |||
1 | /* $NetBSD: bwfm.c,v 1.19 2019/12/27 09:22:20 msaitoh Exp $ */ | 1 | /* $NetBSD: bwfm.c,v 1.20 2020/01/29 14:14:55 thorpej Exp $ */ | |
2 | /* $OpenBSD: bwfm.c,v 1.5 2017/10/16 22:27:16 patrick Exp $ */ | 2 | /* $OpenBSD: bwfm.c,v 1.5 2017/10/16 22:27:16 patrick Exp $ */ | |
3 | /* | 3 | /* | |
4 | * Copyright (c) 2010-2016 Broadcom Corporation | 4 | * Copyright (c) 2010-2016 Broadcom Corporation | |
5 | * Copyright (c) 2016,2017 Patrick Wildt <patrick@blueri.se> | 5 | * Copyright (c) 2016,2017 Patrick Wildt <patrick@blueri.se> | |
6 | * | 6 | * | |
7 | * Permission to use, copy, modify, and/or distribute this software for any | 7 | * Permission to use, copy, modify, and/or distribute this software for any | |
8 | * purpose with or without fee is hereby granted, provided that the above | 8 | * purpose with or without fee is hereby granted, provided that the above | |
9 | * copyright notice and this permission notice appear in all copies. | 9 | * copyright notice and this permission notice appear in all copies. | |
10 | * | 10 | * | |
11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | 11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | 12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | 13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | 14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | 15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
16 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | 16 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
17 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | 17 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
18 | */ | 18 | */ | |
19 | 19 | |||
20 | #include <sys/param.h> | 20 | #include <sys/param.h> | |
21 | #include <sys/systm.h> | 21 | #include <sys/systm.h> | |
22 | #include <sys/buf.h> | 22 | #include <sys/buf.h> | |
23 | #include <sys/kernel.h> | 23 | #include <sys/kernel.h> | |
24 | #include <sys/device.h> | 24 | #include <sys/device.h> | |
25 | #include <sys/queue.h> | 25 | #include <sys/queue.h> | |
26 | #include <sys/socket.h> | 26 | #include <sys/socket.h> | |
27 | #include <sys/kmem.h> | 27 | #include <sys/kmem.h> | |
28 | #include <sys/workqueue.h> | 28 | #include <sys/workqueue.h> | |
29 | #include <sys/pcq.h> | 29 | #include <sys/pcq.h> | |
30 | 30 | |||
31 | #include <net/bpf.h> | 31 | #include <net/bpf.h> | |
32 | #include <net/if.h> | 32 | #include <net/if.h> | |
33 | #include <net/if_dl.h> | 33 | #include <net/if_dl.h> | |
34 | #include <net/if_media.h> | 34 | #include <net/if_media.h> | |
35 | #include <net/if_ether.h> | 35 | #include <net/if_ether.h> | |
36 | 36 | |||
37 | #include <netinet/in.h> | 37 | #include <netinet/in.h> | |
38 | 38 | |||
39 | #include <net80211/ieee80211_var.h> | 39 | #include <net80211/ieee80211_var.h> | |
40 | 40 | |||
41 | #include <dev/ic/bwfmvar.h> | 41 | #include <dev/ic/bwfmvar.h> | |
42 | #include <dev/ic/bwfmreg.h> | 42 | #include <dev/ic/bwfmreg.h> | |
43 | 43 | |||
44 | /* #define BWFM_DEBUG */ | 44 | /* #define BWFM_DEBUG */ | |
45 | #ifdef BWFM_DEBUG | 45 | #ifdef BWFM_DEBUG | |
46 | #define DPRINTF(x) do { if (bwfm_debug > 0) printf x; } while (0) | 46 | #define DPRINTF(x) do { if (bwfm_debug > 0) printf x; } while (0) | |
47 | #define DPRINTFN(n, x) do { if (bwfm_debug >= (n)) printf x; } while (0) | 47 | #define DPRINTFN(n, x) do { if (bwfm_debug >= (n)) printf x; } while (0) | |
48 | static int bwfm_debug = 1; | 48 | static int bwfm_debug = 1; | |
49 | #else | 49 | #else | |
50 | #define DPRINTF(x) do { ; } while (0) | 50 | #define DPRINTF(x) do { ; } while (0) | |
51 | #define DPRINTFN(n, x) do { ; } while (0) | 51 | #define DPRINTFN(n, x) do { ; } while (0) | |
52 | #endif | 52 | #endif | |
53 | 53 | |||
54 | #define DEVNAME(sc) device_xname((sc)->sc_dev) | 54 | #define DEVNAME(sc) device_xname((sc)->sc_dev) | |
55 | 55 | |||
56 | void bwfm_start(struct ifnet *); | 56 | void bwfm_start(struct ifnet *); | |
57 | int bwfm_init(struct ifnet *); | 57 | int bwfm_init(struct ifnet *); | |
58 | void bwfm_stop(struct ifnet *, int); | 58 | void bwfm_stop(struct ifnet *, int); | |
59 | void bwfm_watchdog(struct ifnet *); | 59 | void bwfm_watchdog(struct ifnet *); | |
60 | int bwfm_ioctl(struct ifnet *, u_long, void *); | 60 | int bwfm_ioctl(struct ifnet *, u_long, void *); | |
61 | int bwfm_media_change(struct ifnet *); | 61 | int bwfm_media_change(struct ifnet *); | |
62 | 62 | |||
63 | int bwfm_send_mgmt(struct ieee80211com *, struct ieee80211_node *, | 63 | int bwfm_send_mgmt(struct ieee80211com *, struct ieee80211_node *, | |
64 | int, int); | 64 | int, int); | |
65 | void bwfm_recv_mgmt(struct ieee80211com *, struct mbuf *, | 65 | void bwfm_recv_mgmt(struct ieee80211com *, struct mbuf *, | |
66 | struct ieee80211_node *, int, int, uint32_t); | 66 | struct ieee80211_node *, int, int, uint32_t); | |
67 | int bwfm_key_set(struct ieee80211com *, const struct ieee80211_key *, | 67 | int bwfm_key_set(struct ieee80211com *, const struct ieee80211_key *, | |
68 | const uint8_t *); | 68 | const uint8_t *); | |
69 | int bwfm_key_delete(struct ieee80211com *, const struct ieee80211_key *); | 69 | int bwfm_key_delete(struct ieee80211com *, const struct ieee80211_key *); | |
70 | int bwfm_newstate(struct ieee80211com *, enum ieee80211_state, int); | 70 | int bwfm_newstate(struct ieee80211com *, enum ieee80211_state, int); | |
71 | void bwfm_newstate_cb(struct bwfm_softc *, struct bwfm_cmd_newstate *); | 71 | void bwfm_newstate_cb(struct bwfm_softc *, struct bwfm_cmd_newstate *); | |
72 | void bwfm_newassoc(struct ieee80211_node *, int); | 72 | void bwfm_newassoc(struct ieee80211_node *, int); | |
73 | void bwfm_task(struct work *, void *); | 73 | void bwfm_task(struct work *, void *); | |
74 | 74 | |||
75 | int bwfm_chip_attach(struct bwfm_softc *); | 75 | int bwfm_chip_attach(struct bwfm_softc *); | |
76 | int bwfm_chip_detach(struct bwfm_softc *, int); | 76 | int bwfm_chip_detach(struct bwfm_softc *, int); | |
77 | struct bwfm_core *bwfm_chip_get_core(struct bwfm_softc *, int); | 77 | struct bwfm_core *bwfm_chip_get_core(struct bwfm_softc *, int); | |
78 | struct bwfm_core *bwfm_chip_get_pmu(struct bwfm_softc *); | 78 | struct bwfm_core *bwfm_chip_get_pmu(struct bwfm_softc *); | |
79 | int bwfm_chip_ai_isup(struct bwfm_softc *, struct bwfm_core *); | 79 | int bwfm_chip_ai_isup(struct bwfm_softc *, struct bwfm_core *); | |
80 | void bwfm_chip_ai_disable(struct bwfm_softc *, struct bwfm_core *, | 80 | void bwfm_chip_ai_disable(struct bwfm_softc *, struct bwfm_core *, | |
81 | uint32_t, uint32_t); | 81 | uint32_t, uint32_t); | |
82 | void bwfm_chip_ai_reset(struct bwfm_softc *, struct bwfm_core *, | 82 | void bwfm_chip_ai_reset(struct bwfm_softc *, struct bwfm_core *, | |
83 | uint32_t, uint32_t, uint32_t); | 83 | uint32_t, uint32_t, uint32_t); | |
84 | void bwfm_chip_dmp_erom_scan(struct bwfm_softc *); | 84 | void bwfm_chip_dmp_erom_scan(struct bwfm_softc *); | |
85 | int bwfm_chip_dmp_get_regaddr(struct bwfm_softc *, uint32_t *, | 85 | int bwfm_chip_dmp_get_regaddr(struct bwfm_softc *, uint32_t *, | |
86 | uint32_t *, uint32_t *); | 86 | uint32_t *, uint32_t *); | |
87 | int bwfm_chip_cr4_set_active(struct bwfm_softc *, const uint32_t); | 87 | int bwfm_chip_cr4_set_active(struct bwfm_softc *, const uint32_t); | |
88 | void bwfm_chip_cr4_set_passive(struct bwfm_softc *); | 88 | void bwfm_chip_cr4_set_passive(struct bwfm_softc *); | |
89 | int bwfm_chip_ca7_set_active(struct bwfm_softc *, const uint32_t); | 89 | int bwfm_chip_ca7_set_active(struct bwfm_softc *, const uint32_t); | |
90 | void bwfm_chip_ca7_set_passive(struct bwfm_softc *); | 90 | void bwfm_chip_ca7_set_passive(struct bwfm_softc *); | |
91 | int bwfm_chip_cm3_set_active(struct bwfm_softc *); | 91 | int bwfm_chip_cm3_set_active(struct bwfm_softc *); | |
92 | void bwfm_chip_cm3_set_passive(struct bwfm_softc *); | 92 | void bwfm_chip_cm3_set_passive(struct bwfm_softc *); | |
93 | void bwfm_chip_socram_ramsize(struct bwfm_softc *, struct bwfm_core *); | 93 | void bwfm_chip_socram_ramsize(struct bwfm_softc *, struct bwfm_core *); | |
94 | void bwfm_chip_sysmem_ramsize(struct bwfm_softc *, struct bwfm_core *); | 94 | void bwfm_chip_sysmem_ramsize(struct bwfm_softc *, struct bwfm_core *); | |
95 | void bwfm_chip_tcm_ramsize(struct bwfm_softc *, struct bwfm_core *); | 95 | void bwfm_chip_tcm_ramsize(struct bwfm_softc *, struct bwfm_core *); | |
96 | void bwfm_chip_tcm_rambase(struct bwfm_softc *); | 96 | void bwfm_chip_tcm_rambase(struct bwfm_softc *); | |
97 | 97 | |||
98 | int bwfm_proto_bcdc_query_dcmd(struct bwfm_softc *, int, | 98 | int bwfm_proto_bcdc_query_dcmd(struct bwfm_softc *, int, | |
99 | int, char *, size_t *); | 99 | int, char *, size_t *); | |
100 | int bwfm_proto_bcdc_set_dcmd(struct bwfm_softc *, int, | 100 | int bwfm_proto_bcdc_set_dcmd(struct bwfm_softc *, int, | |
101 | int, char *, size_t); | 101 | int, char *, size_t); | |
102 | 102 | |||
103 | int bwfm_fwvar_cmd_get_data(struct bwfm_softc *, int, void *, size_t); | 103 | int bwfm_fwvar_cmd_get_data(struct bwfm_softc *, int, void *, size_t); | |
104 | int bwfm_fwvar_cmd_set_data(struct bwfm_softc *, int, void *, size_t); | 104 | int bwfm_fwvar_cmd_set_data(struct bwfm_softc *, int, void *, size_t); | |
105 | int bwfm_fwvar_cmd_get_int(struct bwfm_softc *, int, uint32_t *); | 105 | int bwfm_fwvar_cmd_get_int(struct bwfm_softc *, int, uint32_t *); | |
106 | int bwfm_fwvar_cmd_set_int(struct bwfm_softc *, int, uint32_t); | 106 | int bwfm_fwvar_cmd_set_int(struct bwfm_softc *, int, uint32_t); | |
107 | int bwfm_fwvar_var_get_data(struct bwfm_softc *, const char *, void *, size_t); | 107 | int bwfm_fwvar_var_get_data(struct bwfm_softc *, const char *, void *, size_t); | |
108 | int bwfm_fwvar_var_set_data(struct bwfm_softc *, const char *, void *, size_t); | 108 | int bwfm_fwvar_var_set_data(struct bwfm_softc *, const char *, void *, size_t); | |
109 | int bwfm_fwvar_var_get_int(struct bwfm_softc *, const char *, uint32_t *); | 109 | int bwfm_fwvar_var_get_int(struct bwfm_softc *, const char *, uint32_t *); | |
110 | int bwfm_fwvar_var_set_int(struct bwfm_softc *, const char *, uint32_t); | 110 | int bwfm_fwvar_var_set_int(struct bwfm_softc *, const char *, uint32_t); | |
111 | 111 | |||
112 | struct ieee80211_channel *bwfm_bss2chan(struct bwfm_softc *, struct bwfm_bss_info *); | 112 | struct ieee80211_channel *bwfm_bss2chan(struct bwfm_softc *, struct bwfm_bss_info *); | |
113 | void bwfm_scan(struct bwfm_softc *); | 113 | void bwfm_scan(struct bwfm_softc *); | |
114 | void bwfm_connect(struct bwfm_softc *); | 114 | void bwfm_connect(struct bwfm_softc *); | |
115 | void bwfm_get_sta_info(struct bwfm_softc *, struct ifmediareq *); | 115 | void bwfm_get_sta_info(struct bwfm_softc *, struct ifmediareq *); | |
116 | 116 | |||
117 | void bwfm_rx(struct bwfm_softc *, struct mbuf *); | 117 | void bwfm_rx(struct bwfm_softc *, struct mbuf *); | |
118 | void bwfm_rx_event(struct bwfm_softc *, struct mbuf *); | 118 | void bwfm_rx_event(struct bwfm_softc *, struct mbuf *); | |
119 | void bwfm_rx_event_cb(struct bwfm_softc *, struct mbuf *); | 119 | void bwfm_rx_event_cb(struct bwfm_softc *, struct mbuf *); | |
120 | void bwfm_scan_node(struct bwfm_softc *, struct bwfm_bss_info *, size_t); | 120 | void bwfm_scan_node(struct bwfm_softc *, struct bwfm_bss_info *, size_t); | |
121 | 121 | |||
122 | uint8_t bwfm_2ghz_channels[] = { | 122 | uint8_t bwfm_2ghz_channels[] = { | |
123 | 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, | 123 | 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, | |
124 | }; | 124 | }; | |
125 | uint8_t bwfm_5ghz_channels[] = { | 125 | uint8_t bwfm_5ghz_channels[] = { | |
126 | 34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64, 100, 104, 108, 112, | 126 | 34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64, 100, 104, 108, 112, | |
127 | 116, 120, 124, 128, 132, 136, 140, 144, 149, 153, 157, 161, 165, | 127 | 116, 120, 124, 128, 132, 136, 140, 144, 149, 153, 157, 161, 165, | |
128 | }; | 128 | }; | |
129 | 129 | |||
130 | struct bwfm_proto_ops bwfm_proto_bcdc_ops = { | 130 | struct bwfm_proto_ops bwfm_proto_bcdc_ops = { | |
131 | .proto_query_dcmd = bwfm_proto_bcdc_query_dcmd, | 131 | .proto_query_dcmd = bwfm_proto_bcdc_query_dcmd, | |
132 | .proto_set_dcmd = bwfm_proto_bcdc_set_dcmd, | 132 | .proto_set_dcmd = bwfm_proto_bcdc_set_dcmd, | |
133 | }; | 133 | }; | |
134 | 134 | |||
135 | void | 135 | void | |
136 | bwfm_attach(struct bwfm_softc *sc) | 136 | bwfm_attach(struct bwfm_softc *sc) | |
137 | { | 137 | { | |
138 | struct ieee80211com *ic = &sc->sc_ic; | 138 | struct ieee80211com *ic = &sc->sc_ic; | |
139 | struct ifnet *ifp = &sc->sc_if; | 139 | struct ifnet *ifp = &sc->sc_if; | |
140 | struct bwfm_task *t; | 140 | struct bwfm_task *t; | |
141 | char fw_version[BWFM_DCMD_SMLEN]; | 141 | char fw_version[BWFM_DCMD_SMLEN]; | |
142 | uint32_t bandlist[3]; | 142 | uint32_t bandlist[3]; | |
143 | uint32_t tmp; | 143 | uint32_t tmp; | |
144 | int i, j, error; | 144 | int i, j, error; | |
145 | 145 | |||
146 | error = workqueue_create(&sc->sc_taskq, DEVNAME(sc), | 146 | error = workqueue_create(&sc->sc_taskq, DEVNAME(sc), | |
147 | bwfm_task, sc, PRI_NONE, IPL_NET, 0); | 147 | bwfm_task, sc, PRI_NONE, IPL_NET, 0); | |
148 | if (error != 0) { | 148 | if (error != 0) { | |
149 | printf("%s: could not create workqueue\n", DEVNAME(sc)); | 149 | printf("%s: could not create workqueue\n", DEVNAME(sc)); | |
150 | return; | 150 | return; | |
151 | } | 151 | } | |
152 | sc->sc_freetask = pcq_create(BWFM_TASK_COUNT, KM_SLEEP); | 152 | sc->sc_freetask = pcq_create(BWFM_TASK_COUNT, KM_SLEEP); | |
153 | for (i = 0; i < BWFM_TASK_COUNT; i++) { | 153 | for (i = 0; i < BWFM_TASK_COUNT; i++) { | |
154 | t = &sc->sc_task[i]; | 154 | t = &sc->sc_task[i]; | |
155 | t->t_sc = sc; | 155 | t->t_sc = sc; | |
156 | pcq_put(sc->sc_freetask, t); | 156 | pcq_put(sc->sc_freetask, t); | |
157 | } | 157 | } | |
158 | 158 | |||
159 | /* Stop the device in case it was previously initialized */ | 159 | /* Stop the device in case it was previously initialized */ | |
160 | bwfm_fwvar_cmd_set_int(sc, BWFM_C_DOWN, 1); | 160 | bwfm_fwvar_cmd_set_int(sc, BWFM_C_DOWN, 1); | |
161 | 161 | |||
162 | if (bwfm_fwvar_cmd_get_int(sc, BWFM_C_GET_VERSION, &tmp)) { | 162 | if (bwfm_fwvar_cmd_get_int(sc, BWFM_C_GET_VERSION, &tmp)) { | |
163 | printf("%s: could not read io type\n", DEVNAME(sc)); | 163 | printf("%s: could not read io type\n", DEVNAME(sc)); | |
164 | return; | 164 | return; | |
165 | } else | 165 | } else | |
166 | sc->sc_io_type = tmp; | 166 | sc->sc_io_type = tmp; | |
167 | if (bwfm_fwvar_var_get_data(sc, "cur_etheraddr", ic->ic_myaddr, | 167 | if (bwfm_fwvar_var_get_data(sc, "cur_etheraddr", ic->ic_myaddr, | |
168 | sizeof(ic->ic_myaddr))) { | 168 | sizeof(ic->ic_myaddr))) { | |
169 | printf("%s: could not read mac address\n", DEVNAME(sc)); | 169 | printf("%s: could not read mac address\n", DEVNAME(sc)); | |
170 | return; | 170 | return; | |
171 | } | 171 | } | |
172 | 172 | |||
173 | memset(fw_version, 0, sizeof(fw_version)); | 173 | memset(fw_version, 0, sizeof(fw_version)); | |
174 | if (bwfm_fwvar_var_get_data(sc, "ver", fw_version, sizeof(fw_version)) == 0) | 174 | if (bwfm_fwvar_var_get_data(sc, "ver", fw_version, sizeof(fw_version)) == 0) | |
175 | printf("%s: %s", DEVNAME(sc), fw_version); | 175 | printf("%s: %s", DEVNAME(sc), fw_version); | |
176 | printf("%s: address %s\n", DEVNAME(sc), ether_sprintf(ic->ic_myaddr)); | 176 | printf("%s: address %s\n", DEVNAME(sc), ether_sprintf(ic->ic_myaddr)); | |
177 | 177 | |||
178 | ic->ic_ifp = ifp; | 178 | ic->ic_ifp = ifp; | |
179 | ic->ic_phytype = IEEE80211_T_OFDM; | 179 | ic->ic_phytype = IEEE80211_T_OFDM; | |
180 | ic->ic_opmode = IEEE80211_M_STA; | 180 | ic->ic_opmode = IEEE80211_M_STA; | |
181 | ic->ic_state = IEEE80211_S_INIT; | 181 | ic->ic_state = IEEE80211_S_INIT; | |
182 | 182 | |||
183 | ic->ic_caps = | 183 | ic->ic_caps = | |
184 | IEEE80211_C_WEP | | 184 | IEEE80211_C_WEP | | |
185 | IEEE80211_C_TKIP | | 185 | IEEE80211_C_TKIP | | |
186 | IEEE80211_C_AES | | 186 | IEEE80211_C_AES | | |
187 | IEEE80211_C_AES_CCM | | 187 | IEEE80211_C_AES_CCM | | |
188 | #if notyet | 188 | #if notyet | |
189 | IEEE80211_C_MONITOR | /* monitor mode supported */ | 189 | IEEE80211_C_MONITOR | /* monitor mode supported */ | |
190 | IEEE80211_C_IBSS | | 190 | IEEE80211_C_IBSS | | |
191 | IEEE80211_C_TXPMGT | | 191 | IEEE80211_C_TXPMGT | | |
192 | IEEE80211_C_WME | | 192 | IEEE80211_C_WME | | |
193 | #endif | 193 | #endif | |
194 | IEEE80211_C_SHSLOT | /* short slot time supported */ | 194 | IEEE80211_C_SHSLOT | /* short slot time supported */ | |
195 | IEEE80211_C_SHPREAMBLE | /* short preamble supported */ | 195 | IEEE80211_C_SHPREAMBLE | /* short preamble supported */ | |
196 | IEEE80211_C_WPA | /* 802.11i */ | 196 | IEEE80211_C_WPA | /* 802.11i */ | |
197 | /* IEEE80211_C_WPA_4WAY */0; /* WPA 4-way handshake in hw */ | 197 | /* IEEE80211_C_WPA_4WAY */0; /* WPA 4-way handshake in hw */ | |
198 | 198 | |||
199 | /* IBSS channel undefined for now. */ | 199 | /* IBSS channel undefined for now. */ | |
200 | ic->ic_ibss_chan = &ic->ic_channels[0]; | 200 | ic->ic_ibss_chan = &ic->ic_channels[0]; | |
201 | 201 | |||
202 | if (bwfm_fwvar_cmd_get_data(sc, BWFM_C_GET_BANDLIST, bandlist, | 202 | if (bwfm_fwvar_cmd_get_data(sc, BWFM_C_GET_BANDLIST, bandlist, | |
203 | sizeof(bandlist))) { | 203 | sizeof(bandlist))) { | |
204 | printf("%s: couldn't get supported band list\n", DEVNAME(sc)); | 204 | printf("%s: couldn't get supported band list\n", DEVNAME(sc)); | |
205 | return; | 205 | return; | |
206 | } | 206 | } | |
207 | const u_int nbands = le32toh(bandlist[0]); | 207 | const u_int nbands = le32toh(bandlist[0]); | |
208 | for (i = 1; i <= MIN(nbands, __arraycount(bandlist) - 1); i++) { | 208 | for (i = 1; i <= MIN(nbands, __arraycount(bandlist) - 1); i++) { | |
209 | switch (le32toh(bandlist[i])) { | 209 | switch (le32toh(bandlist[i])) { | |
210 | case BWFM_BAND_2G: | 210 | case BWFM_BAND_2G: | |
211 | ic->ic_sup_rates[IEEE80211_MODE_11B] = ieee80211_std_rateset_11b; | 211 | ic->ic_sup_rates[IEEE80211_MODE_11B] = ieee80211_std_rateset_11b; | |
212 | ic->ic_sup_rates[IEEE80211_MODE_11G] = ieee80211_std_rateset_11g; | 212 | ic->ic_sup_rates[IEEE80211_MODE_11G] = ieee80211_std_rateset_11g; | |
213 | 213 | |||
214 | for (j = 0; j < __arraycount(bwfm_2ghz_channels); j++) { | 214 | for (j = 0; j < __arraycount(bwfm_2ghz_channels); j++) { | |
215 | uint8_t chan = bwfm_2ghz_channels[j]; | 215 | uint8_t chan = bwfm_2ghz_channels[j]; | |
216 | ic->ic_channels[chan].ic_freq = | 216 | ic->ic_channels[chan].ic_freq = | |
217 | ieee80211_ieee2mhz(chan, IEEE80211_CHAN_2GHZ); | 217 | ieee80211_ieee2mhz(chan, IEEE80211_CHAN_2GHZ); | |
218 | ic->ic_channels[chan].ic_flags = | 218 | ic->ic_channels[chan].ic_flags = | |
219 | IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM | | 219 | IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM | | |
220 | IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ; | 220 | IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ; | |
221 | } | 221 | } | |
222 | break; | 222 | break; | |
223 | case BWFM_BAND_5G: | 223 | case BWFM_BAND_5G: | |
224 | ic->ic_sup_rates[IEEE80211_MODE_11A] = ieee80211_std_rateset_11a; | 224 | ic->ic_sup_rates[IEEE80211_MODE_11A] = ieee80211_std_rateset_11a; | |
225 | 225 | |||
226 | for (j = 0; j < __arraycount(bwfm_5ghz_channels); j++) { | 226 | for (j = 0; j < __arraycount(bwfm_5ghz_channels); j++) { | |
227 | uint8_t chan = bwfm_5ghz_channels[j]; | 227 | uint8_t chan = bwfm_5ghz_channels[j]; | |
228 | ic->ic_channels[chan].ic_freq = | 228 | ic->ic_channels[chan].ic_freq = | |
229 | ieee80211_ieee2mhz(chan, IEEE80211_CHAN_5GHZ); | 229 | ieee80211_ieee2mhz(chan, IEEE80211_CHAN_5GHZ); | |
230 | ic->ic_channels[chan].ic_flags = | 230 | ic->ic_channels[chan].ic_flags = | |
231 | IEEE80211_CHAN_A; | 231 | IEEE80211_CHAN_A; | |
232 | } | 232 | } | |
233 | break; | 233 | break; | |
234 | } | 234 | } | |
235 | } | 235 | } | |
236 | 236 | |||
237 | ifp->if_softc = sc; | 237 | ifp->if_softc = sc; | |
238 | ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; | 238 | ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; | |
239 | ifp->if_init = bwfm_init; | 239 | ifp->if_init = bwfm_init; | |
240 | ifp->if_ioctl = bwfm_ioctl; | 240 | ifp->if_ioctl = bwfm_ioctl; | |
241 | ifp->if_start = bwfm_start; | 241 | ifp->if_start = bwfm_start; | |
242 | ifp->if_stop = bwfm_stop; | 242 | ifp->if_stop = bwfm_stop; | |
243 | ifp->if_watchdog = bwfm_watchdog; | 243 | ifp->if_watchdog = bwfm_watchdog; | |
244 | IFQ_SET_READY(&ifp->if_snd); | 244 | IFQ_SET_READY(&ifp->if_snd); | |
245 | memcpy(ifp->if_xname, DEVNAME(sc), IFNAMSIZ); | 245 | memcpy(ifp->if_xname, DEVNAME(sc), IFNAMSIZ); | |
246 | 246 | |||
247 | error = if_initialize(ifp); | 247 | error = if_initialize(ifp); | |
248 | if (error != 0) { | 248 | if (error != 0) { | |
249 | printf("%s: if_initialize failed(%d)\n", DEVNAME(sc), error); | 249 | printf("%s: if_initialize failed(%d)\n", DEVNAME(sc), error); | |
250 | pcq_destroy(sc->sc_freetask); | 250 | pcq_destroy(sc->sc_freetask); | |
251 | workqueue_destroy(sc->sc_taskq); | 251 | workqueue_destroy(sc->sc_taskq); | |
252 | 252 | |||
253 | return; /* Error */ | 253 | return; /* Error */ | |
254 | } | 254 | } | |
255 | 255 | |||
256 | ieee80211_ifattach(ic); | 256 | ieee80211_ifattach(ic); | |
257 | ifp->if_percpuq = if_percpuq_create(ifp); | 257 | ifp->if_percpuq = if_percpuq_create(ifp); | |
258 | if_deferred_start_init(ifp, NULL); | 258 | if_deferred_start_init(ifp, NULL); | |
259 | if_register(ifp); | 259 | if_register(ifp); | |
260 | 260 | |||
261 | sc->sc_newstate = ic->ic_newstate; | 261 | sc->sc_newstate = ic->ic_newstate; | |
262 | ic->ic_newstate = bwfm_newstate; | 262 | ic->ic_newstate = bwfm_newstate; | |
263 | ic->ic_newassoc = bwfm_newassoc; | 263 | ic->ic_newassoc = bwfm_newassoc; | |
264 | ic->ic_send_mgmt = bwfm_send_mgmt; | 264 | ic->ic_send_mgmt = bwfm_send_mgmt; | |
265 | ic->ic_recv_mgmt = bwfm_recv_mgmt; | 265 | ic->ic_recv_mgmt = bwfm_recv_mgmt; | |
266 | ic->ic_crypto.cs_key_set = bwfm_key_set; | 266 | ic->ic_crypto.cs_key_set = bwfm_key_set; | |
267 | ic->ic_crypto.cs_key_delete = bwfm_key_delete; | 267 | ic->ic_crypto.cs_key_delete = bwfm_key_delete; | |
268 | ieee80211_media_init(ic, bwfm_media_change, ieee80211_media_status); | 268 | ieee80211_media_init(ic, bwfm_media_change, ieee80211_media_status); | |
269 | 269 | |||
270 | ieee80211_announce(ic); | 270 | ieee80211_announce(ic); | |
271 | 271 | |||
272 | sc->sc_if_attached = true; | 272 | sc->sc_if_attached = true; | |
273 | } | 273 | } | |
274 | 274 | |||
275 | int | 275 | int | |
276 | bwfm_detach(struct bwfm_softc *sc, int flags) | 276 | bwfm_detach(struct bwfm_softc *sc, int flags) | |
277 | { | 277 | { | |
278 | struct ieee80211com *ic = &sc->sc_ic; | 278 | struct ieee80211com *ic = &sc->sc_ic; | |
279 | struct ifnet *ifp = ic->ic_ifp; | 279 | struct ifnet *ifp = ic->ic_ifp; | |
280 | 280 | |||
281 | if (sc->sc_if_attached) { | 281 | if (sc->sc_if_attached) { | |
282 | bpf_detach(ifp); | 282 | bpf_detach(ifp); | |
283 | ieee80211_ifdetach(ic); | 283 | ieee80211_ifdetach(ic); | |
284 | if_detach(ifp); | 284 | if_detach(ifp); | |
285 | } | 285 | } | |
286 | 286 | |||
287 | if (sc->sc_taskq) | 287 | if (sc->sc_taskq) | |
288 | workqueue_destroy(sc->sc_taskq); | 288 | workqueue_destroy(sc->sc_taskq); | |
289 | if (sc->sc_freetask) | 289 | if (sc->sc_freetask) | |
290 | pcq_destroy(sc->sc_freetask); | 290 | pcq_destroy(sc->sc_freetask); | |
291 | 291 | |||
292 | return 0; | 292 | return 0; | |
293 | } | 293 | } | |
294 | 294 | |||
295 | void | 295 | void | |
296 | bwfm_start(struct ifnet *ifp) | 296 | bwfm_start(struct ifnet *ifp) | |
297 | { | 297 | { | |
298 | struct bwfm_softc *sc = ifp->if_softc; | 298 | struct bwfm_softc *sc = ifp->if_softc; | |
299 | struct ieee80211com *ic = &sc->sc_ic; | 299 | struct ieee80211com *ic = &sc->sc_ic; | |
300 | struct mbuf *m; | 300 | struct mbuf *m; | |
301 | int error; | 301 | int error; | |
302 | 302 | |||
303 | if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING) | 303 | if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING) | |
304 | return; | 304 | return; | |
305 | 305 | |||
306 | /* TODO: return if no link? */ | 306 | /* TODO: return if no link? */ | |
307 | 307 | |||
308 | for (;;) { | 308 | for (;;) { | |
309 | /* Discard management packets (fw handles this for us) */ | 309 | /* Discard management packets (fw handles this for us) */ | |
310 | IF_DEQUEUE(&ic->ic_mgtq, m); | 310 | IF_DEQUEUE(&ic->ic_mgtq, m); | |
311 | if (m != NULL) { | 311 | if (m != NULL) { | |
312 | m_freem(m); | 312 | m_freem(m); | |
313 | continue; | 313 | continue; | |
314 | } | 314 | } | |
315 | 315 | |||
316 | if (sc->sc_bus_ops->bs_txcheck(sc)) { | 316 | if (sc->sc_bus_ops->bs_txcheck(sc)) { | |
317 | ifp->if_flags |= IFF_OACTIVE; | 317 | ifp->if_flags |= IFF_OACTIVE; | |
318 | break; | 318 | break; | |
319 | } | 319 | } | |
320 | 320 | |||
321 | IFQ_DEQUEUE(&ifp->if_snd, m); | 321 | IFQ_DEQUEUE(&ifp->if_snd, m); | |
322 | if (m == NULL) | 322 | if (m == NULL) | |
323 | break; | 323 | break; | |
324 | 324 | |||
325 | error = sc->sc_bus_ops->bs_txdata(sc, &m); | 325 | error = sc->sc_bus_ops->bs_txdata(sc, &m); | |
326 | if (error == ENOBUFS) { | 326 | if (error == ENOBUFS) { | |
327 | IF_PREPEND(&ifp->if_snd, m); | 327 | IF_PREPEND(&ifp->if_snd, m); | |
328 | ifp->if_flags |= IFF_OACTIVE; | 328 | ifp->if_flags |= IFF_OACTIVE; | |
329 | break; | 329 | break; | |
330 | } | 330 | } | |
331 | if (error != 0) { | 331 | if (error != 0) { | |
332 | ifp->if_oerrors++; | 332 | if_statinc(ifp, if_oerrors); | |
333 | m_freem(m); | 333 | m_freem(m); | |
334 | continue; | 334 | continue; | |
335 | } | 335 | } | |
336 | 336 | |||
337 | bpf_mtap(ifp, m, BPF_D_OUT); | 337 | bpf_mtap(ifp, m, BPF_D_OUT); | |
338 | } | 338 | } | |
339 | } | 339 | } | |
340 | 340 | |||
341 | int | 341 | int | |
342 | bwfm_init(struct ifnet *ifp) | 342 | bwfm_init(struct ifnet *ifp) | |
343 | { | 343 | { | |
344 | struct bwfm_softc *sc = ifp->if_softc; | 344 | struct bwfm_softc *sc = ifp->if_softc; | |
345 | struct ieee80211com *ic = &sc->sc_ic; | 345 | struct ieee80211com *ic = &sc->sc_ic; | |
346 | uint8_t evmask[BWFM_EVENT_MASK_LEN]; | 346 | uint8_t evmask[BWFM_EVENT_MASK_LEN]; | |
347 | struct bwfm_join_pref_params join_pref[2]; | 347 | struct bwfm_join_pref_params join_pref[2]; | |
348 | int pm; | 348 | int pm; | |
349 | 349 | |||
350 | if (bwfm_fwvar_var_set_int(sc, "mpc", 1)) { | 350 | if (bwfm_fwvar_var_set_int(sc, "mpc", 1)) { | |
351 | printf("%s: could not set mpc\n", DEVNAME(sc)); | 351 | printf("%s: could not set mpc\n", DEVNAME(sc)); | |
352 | return EIO; | 352 | return EIO; | |
353 | } | 353 | } | |
354 | 354 | |||
355 | /* Select target by RSSI (boost on 5GHz) */ | 355 | /* Select target by RSSI (boost on 5GHz) */ | |
356 | join_pref[0].type = BWFM_JOIN_PREF_RSSI_DELTA; | 356 | join_pref[0].type = BWFM_JOIN_PREF_RSSI_DELTA; | |
357 | join_pref[0].len = 2; | 357 | join_pref[0].len = 2; | |
358 | join_pref[0].rssi_gain = BWFM_JOIN_PREF_RSSI_BOOST; | 358 | join_pref[0].rssi_gain = BWFM_JOIN_PREF_RSSI_BOOST; | |
359 | join_pref[0].band = BWFM_JOIN_PREF_BAND_5G; | 359 | join_pref[0].band = BWFM_JOIN_PREF_BAND_5G; | |
360 | join_pref[1].type = BWFM_JOIN_PREF_RSSI; | 360 | join_pref[1].type = BWFM_JOIN_PREF_RSSI; | |
361 | join_pref[1].len = 2; | 361 | join_pref[1].len = 2; | |
362 | join_pref[1].rssi_gain = 0; | 362 | join_pref[1].rssi_gain = 0; | |
363 | join_pref[1].band = 0; | 363 | join_pref[1].band = 0; | |
364 | if (bwfm_fwvar_var_set_data(sc, "join_pref", join_pref, | 364 | if (bwfm_fwvar_var_set_data(sc, "join_pref", join_pref, | |
365 | sizeof(join_pref))) { | 365 | sizeof(join_pref))) { | |
366 | printf("%s: could not set join pref\n", DEVNAME(sc)); | 366 | printf("%s: could not set join pref\n", DEVNAME(sc)); | |
367 | return EIO; | 367 | return EIO; | |
368 | } | 368 | } | |
369 | 369 | |||
370 | memset(evmask, 0, sizeof(evmask)); | 370 | memset(evmask, 0, sizeof(evmask)); | |
371 | 371 | |||
372 | #define ENABLE_EVENT(e) evmask[(e) / 8] |= 1 << ((e) % 8) | 372 | #define ENABLE_EVENT(e) evmask[(e) / 8] |= 1 << ((e) % 8) | |
373 | /* Events used to drive the state machine */ | 373 | /* Events used to drive the state machine */ | |
374 | switch (ic->ic_opmode) { | 374 | switch (ic->ic_opmode) { | |
375 | case IEEE80211_M_STA: | 375 | case IEEE80211_M_STA: | |
376 | ENABLE_EVENT(BWFM_E_IF); | 376 | ENABLE_EVENT(BWFM_E_IF); | |
377 | ENABLE_EVENT(BWFM_E_LINK); | 377 | ENABLE_EVENT(BWFM_E_LINK); | |
378 | ENABLE_EVENT(BWFM_E_AUTH); | 378 | ENABLE_EVENT(BWFM_E_AUTH); | |
379 | ENABLE_EVENT(BWFM_E_ASSOC); | 379 | ENABLE_EVENT(BWFM_E_ASSOC); | |
380 | ENABLE_EVENT(BWFM_E_DEAUTH); | 380 | ENABLE_EVENT(BWFM_E_DEAUTH); | |
381 | ENABLE_EVENT(BWFM_E_DISASSOC); | 381 | ENABLE_EVENT(BWFM_E_DISASSOC); | |
382 | ENABLE_EVENT(BWFM_E_SET_SSID); | 382 | ENABLE_EVENT(BWFM_E_SET_SSID); | |
383 | ENABLE_EVENT(BWFM_E_ESCAN_RESULT); | 383 | ENABLE_EVENT(BWFM_E_ESCAN_RESULT); | |
384 | break; | 384 | break; | |
385 | #ifndef IEEE80211_STA_ONLY | 385 | #ifndef IEEE80211_STA_ONLY | |
386 | case IEEE80211_M_HOSTAP: | 386 | case IEEE80211_M_HOSTAP: | |
387 | ENABLE_EVENT(BWFM_E_AUTH_IND); | 387 | ENABLE_EVENT(BWFM_E_AUTH_IND); | |
388 | ENABLE_EVENT(BWFM_E_ASSOC_IND); | 388 | ENABLE_EVENT(BWFM_E_ASSOC_IND); | |
389 | ENABLE_EVENT(BWFM_E_REASSOC_IND); | 389 | ENABLE_EVENT(BWFM_E_REASSOC_IND); | |
390 | ENABLE_EVENT(BWFM_E_DEAUTH_IND); | 390 | ENABLE_EVENT(BWFM_E_DEAUTH_IND); | |
391 | ENABLE_EVENT(BWFM_E_DISASSOC_IND); | 391 | ENABLE_EVENT(BWFM_E_DISASSOC_IND); | |
392 | ENABLE_EVENT(BWFM_E_ESCAN_RESULT); | 392 | ENABLE_EVENT(BWFM_E_ESCAN_RESULT); | |
393 | ENABLE_EVENT(BWFM_E_ESCAN_RESULT); | 393 | ENABLE_EVENT(BWFM_E_ESCAN_RESULT); | |
394 | break; | 394 | break; | |
395 | #endif | 395 | #endif | |
396 | default: | 396 | default: | |
397 | break; | 397 | break; | |
398 | } | 398 | } | |
399 | #undef ENABLE_EVENT | 399 | #undef ENABLE_EVENT | |
400 | 400 | |||
401 | #ifdef BWFM_DEBUG | 401 | #ifdef BWFM_DEBUG | |
402 | memset(evmask, 0xff, sizeof(evmask)); | 402 | memset(evmask, 0xff, sizeof(evmask)); | |
403 | #endif | 403 | #endif | |
404 | 404 | |||
405 | if (bwfm_fwvar_var_set_data(sc, "event_msgs", evmask, sizeof(evmask))) { | 405 | if (bwfm_fwvar_var_set_data(sc, "event_msgs", evmask, sizeof(evmask))) { | |
406 | printf("%s: could not set event mask\n", DEVNAME(sc)); | 406 | printf("%s: could not set event mask\n", DEVNAME(sc)); | |
407 | return EIO; | 407 | return EIO; | |
408 | } | 408 | } | |
409 | 409 | |||
410 | if (bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_SCAN_CHANNEL_TIME, | 410 | if (bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_SCAN_CHANNEL_TIME, | |
411 | BWFM_DEFAULT_SCAN_CHANNEL_TIME)) { | 411 | BWFM_DEFAULT_SCAN_CHANNEL_TIME)) { | |
412 | printf("%s: could not set scan channel time\n", DEVNAME(sc)); | 412 | printf("%s: could not set scan channel time\n", DEVNAME(sc)); | |
413 | return EIO; | 413 | return EIO; | |
414 | } | 414 | } | |
415 | if (bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_SCAN_UNASSOC_TIME, | 415 | if (bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_SCAN_UNASSOC_TIME, | |
416 | BWFM_DEFAULT_SCAN_UNASSOC_TIME)) { | 416 | BWFM_DEFAULT_SCAN_UNASSOC_TIME)) { | |
417 | printf("%s: could not set scan unassoc time\n", DEVNAME(sc)); | 417 | printf("%s: could not set scan unassoc time\n", DEVNAME(sc)); | |
418 | return EIO; | 418 | return EIO; | |
419 | } | 419 | } | |
420 | if (bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_SCAN_PASSIVE_TIME, | 420 | if (bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_SCAN_PASSIVE_TIME, | |
421 | BWFM_DEFAULT_SCAN_PASSIVE_TIME)) { | 421 | BWFM_DEFAULT_SCAN_PASSIVE_TIME)) { | |
422 | printf("%s: could not set scan passive time\n", DEVNAME(sc)); | 422 | printf("%s: could not set scan passive time\n", DEVNAME(sc)); | |
423 | return EIO; | 423 | return EIO; | |
424 | } | 424 | } | |
425 | 425 | |||
426 | /* | 426 | /* | |
427 | * Use CAM (constantly awake) when we are running as AP | 427 | * Use CAM (constantly awake) when we are running as AP | |
428 | * otherwise use fast power saving. | 428 | * otherwise use fast power saving. | |
429 | */ | 429 | */ | |
430 | pm = BWFM_PM_FAST_PS; | 430 | pm = BWFM_PM_FAST_PS; | |
431 | #ifndef IEEE80211_STA_ONLY | 431 | #ifndef IEEE80211_STA_ONLY | |
432 | if (ic->ic_opmode == IEEE80211_M_HOSTAP) | 432 | if (ic->ic_opmode == IEEE80211_M_HOSTAP) | |
433 | pm = BWFM_PM_CAM; | 433 | pm = BWFM_PM_CAM; | |
434 | #endif | 434 | #endif | |
435 | if (bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_PM, pm)) { | 435 | if (bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_PM, pm)) { | |
436 | printf("%s: could not set power\n", DEVNAME(sc)); | 436 | printf("%s: could not set power\n", DEVNAME(sc)); | |
437 | return EIO; | 437 | return EIO; | |
438 | } | 438 | } | |
439 | 439 | |||
440 | bwfm_fwvar_var_set_int(sc, "txbf", 1); | 440 | bwfm_fwvar_var_set_int(sc, "txbf", 1); | |
441 | bwfm_fwvar_cmd_set_int(sc, BWFM_C_UP, 0); | 441 | bwfm_fwvar_cmd_set_int(sc, BWFM_C_UP, 0); | |
442 | bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_INFRA, 1); | 442 | bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_INFRA, 1); | |
443 | bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_AP, 0); | 443 | bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_AP, 0); | |
444 | 444 | |||
445 | /* Disable all offloading (ARP, NDP, TCP/UDP cksum). */ | 445 | /* Disable all offloading (ARP, NDP, TCP/UDP cksum). */ | |
446 | bwfm_fwvar_var_set_int(sc, "arp_ol", 0); | 446 | bwfm_fwvar_var_set_int(sc, "arp_ol", 0); | |
447 | bwfm_fwvar_var_set_int(sc, "arpoe", 0); | 447 | bwfm_fwvar_var_set_int(sc, "arpoe", 0); | |
448 | bwfm_fwvar_var_set_int(sc, "ndoe", 0); | 448 | bwfm_fwvar_var_set_int(sc, "ndoe", 0); | |
449 | bwfm_fwvar_var_set_int(sc, "toe", 0); | 449 | bwfm_fwvar_var_set_int(sc, "toe", 0); | |
450 | 450 | |||
451 | /* Accept all multicast frames. */ | 451 | /* Accept all multicast frames. */ | |
452 | bwfm_fwvar_var_set_int(sc, "allmulti", 1); | 452 | bwfm_fwvar_var_set_int(sc, "allmulti", 1); | |
453 | 453 | |||
454 | /* Setup promiscuous mode */ | 454 | /* Setup promiscuous mode */ | |
455 | bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_PROMISC, | 455 | bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_PROMISC, | |
456 | (ifp->if_flags & IFF_PROMISC) ? 1 : 0); | 456 | (ifp->if_flags & IFF_PROMISC) ? 1 : 0); | |
457 | 457 | |||
458 | /* | 458 | /* | |
459 | * Tell the firmware supplicant that we are going to handle the | 459 | * Tell the firmware supplicant that we are going to handle the | |
460 | * WPA handshake ourselves. | 460 | * WPA handshake ourselves. | |
461 | */ | 461 | */ | |
462 | bwfm_fwvar_var_set_int(sc, "sup_wpa", 0); | 462 | bwfm_fwvar_var_set_int(sc, "sup_wpa", 0); | |
463 | 463 | |||
464 | ifp->if_flags |= IFF_RUNNING; | 464 | ifp->if_flags |= IFF_RUNNING; | |
465 | ifp->if_flags &= ~IFF_OACTIVE; | 465 | ifp->if_flags &= ~IFF_OACTIVE; | |
466 | 466 | |||
467 | if (ic->ic_opmode != IEEE80211_M_MONITOR) { | 467 | if (ic->ic_opmode != IEEE80211_M_MONITOR) { | |
468 | if (ic->ic_roaming != IEEE80211_ROAMING_MANUAL) | 468 | if (ic->ic_roaming != IEEE80211_ROAMING_MANUAL) | |
469 | ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); | 469 | ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); | |
470 | } else { | 470 | } else { | |
471 | ieee80211_new_state(ic, IEEE80211_S_RUN, -1); | 471 | ieee80211_new_state(ic, IEEE80211_S_RUN, -1); | |
472 | } | 472 | } | |
473 | 473 | |||
474 | return 0; | 474 | return 0; | |
475 | } | 475 | } | |
476 | 476 | |||
477 | void | 477 | void | |
478 | bwfm_stop(struct ifnet *ifp, int disable) | 478 | bwfm_stop(struct ifnet *ifp, int disable) | |
479 | { | 479 | { | |
480 | struct bwfm_softc *sc = ifp->if_softc; | 480 | struct bwfm_softc *sc = ifp->if_softc; | |
481 | struct ieee80211com *ic = &sc->sc_ic; | 481 | struct ieee80211com *ic = &sc->sc_ic; | |
482 | struct bwfm_join_params join; | 482 | struct bwfm_join_params join; | |
483 | 483 | |||
484 | sc->sc_tx_timer = 0; | 484 | sc->sc_tx_timer = 0; | |
485 | ifp->if_timer = 0; | 485 | ifp->if_timer = 0; | |
486 | ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); | 486 | ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); | |
487 | 487 | |||
488 | memset(&join, 0, sizeof(join)); | 488 | memset(&join, 0, sizeof(join)); | |
489 | bwfm_fwvar_cmd_set_data(sc, BWFM_C_SET_SSID, &join, sizeof(join)); | 489 | bwfm_fwvar_cmd_set_data(sc, BWFM_C_SET_SSID, &join, sizeof(join)); | |
490 | bwfm_fwvar_cmd_set_int(sc, BWFM_C_DOWN, 1); | 490 | bwfm_fwvar_cmd_set_int(sc, BWFM_C_DOWN, 1); | |
491 | bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_PM, 0); | 491 | bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_PM, 0); | |
492 | bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_AP, 0); | 492 | bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_AP, 0); | |
493 | bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_INFRA, 0); | 493 | bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_INFRA, 0); | |
494 | bwfm_fwvar_cmd_set_int(sc, BWFM_C_UP, 1); | 494 | bwfm_fwvar_cmd_set_int(sc, BWFM_C_UP, 1); | |
495 | bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_PM, BWFM_PM_FAST_PS); | 495 | bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_PM, BWFM_PM_FAST_PS); | |
496 | 496 | |||
497 | ieee80211_new_state(ic, IEEE80211_S_INIT, -1); | 497 | ieee80211_new_state(ic, IEEE80211_S_INIT, -1); | |
498 | 498 | |||
499 | if (sc->sc_bus_ops->bs_stop) | 499 | if (sc->sc_bus_ops->bs_stop) | |
500 | sc->sc_bus_ops->bs_stop(sc); | 500 | sc->sc_bus_ops->bs_stop(sc); | |
501 | } | 501 | } | |
502 | 502 | |||
503 | void | 503 | void | |
504 | bwfm_watchdog(struct ifnet *ifp) | 504 | bwfm_watchdog(struct ifnet *ifp) | |
505 | { | 505 | { | |
506 | struct bwfm_softc *sc = ifp->if_softc; | 506 | struct bwfm_softc *sc = ifp->if_softc; | |
507 | struct ieee80211com *ic = &sc->sc_ic; | 507 | struct ieee80211com *ic = &sc->sc_ic; | |
508 | 508 | |||
509 | ifp->if_timer = 0; | 509 | ifp->if_timer = 0; | |
510 | 510 | |||
511 | if (sc->sc_tx_timer > 0) { | 511 | if (sc->sc_tx_timer > 0) { | |
512 | if (--sc->sc_tx_timer == 0) { | 512 | if (--sc->sc_tx_timer == 0) { | |
513 | printf("%s: device timeout\n", DEVNAME(sc)); | 513 | printf("%s: device timeout\n", DEVNAME(sc)); | |
514 | ifp->if_oerrors++; | 514 | if_statinc(ifp, if_oerrors); | |
515 | return; | 515 | return; | |
516 | } | 516 | } | |
517 | ifp->if_timer = 1; | 517 | ifp->if_timer = 1; | |
518 | } | 518 | } | |
519 | ieee80211_watchdog(ic); | 519 | ieee80211_watchdog(ic); | |
520 | } | 520 | } | |
521 | 521 | |||
522 | int | 522 | int | |
523 | bwfm_ioctl(struct ifnet *ifp, u_long cmd, void *data) | 523 | bwfm_ioctl(struct ifnet *ifp, u_long cmd, void *data) | |
524 | { | 524 | { | |
525 | struct bwfm_softc *sc = ifp->if_softc; | 525 | struct bwfm_softc *sc = ifp->if_softc; | |
526 | struct ieee80211com *ic = &sc->sc_ic; | 526 | struct ieee80211com *ic = &sc->sc_ic; | |
527 | int s, error = 0; | 527 | int s, error = 0; | |
528 | 528 | |||
529 | s = splnet(); | 529 | s = splnet(); | |
530 | 530 | |||
531 | switch (cmd) { | 531 | switch (cmd) { | |
532 | case SIOCSIFFLAGS: | 532 | case SIOCSIFFLAGS: | |
533 | if ((error = ifioctl_common(ifp, cmd, data)) != 0) | 533 | if ((error = ifioctl_common(ifp, cmd, data)) != 0) | |
534 | break; | 534 | break; | |
535 | switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) { | 535 | switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) { | |
536 | case IFF_UP | IFF_RUNNING: | 536 | case IFF_UP | IFF_RUNNING: | |
537 | break; | 537 | break; | |
538 | case IFF_UP: | 538 | case IFF_UP: | |
539 | bwfm_init(ifp); | 539 | bwfm_init(ifp); | |
540 | break; | 540 | break; | |
541 | case IFF_RUNNING: | 541 | case IFF_RUNNING: | |
542 | bwfm_stop(ifp, 1); | 542 | bwfm_stop(ifp, 1); | |
543 | break; | 543 | break; | |
544 | case 0: | 544 | case 0: | |
545 | break; | 545 | break; | |
546 | } | 546 | } | |
547 | break; | 547 | break; | |
548 | 548 | |||
549 | case SIOCADDMULTI: | 549 | case SIOCADDMULTI: | |
550 | case SIOCDELMULTI: | 550 | case SIOCDELMULTI: | |
551 | if ((error = ether_ioctl(ifp, cmd, data)) == ENETRESET) { | 551 | if ((error = ether_ioctl(ifp, cmd, data)) == ENETRESET) { | |
552 | /* setup multicast filter, etc */ | 552 | /* setup multicast filter, etc */ | |
553 | error = 0; | 553 | error = 0; | |
554 | } | 554 | } | |
555 | break; | 555 | break; | |
556 | 556 | |||
557 | case SIOCGIFMEDIA: | 557 | case SIOCGIFMEDIA: | |
558 | error = ieee80211_ioctl(ic, cmd, data); | 558 | error = ieee80211_ioctl(ic, cmd, data); | |
559 | if (error == 0 && ic->ic_state == IEEE80211_S_RUN) | 559 | if (error == 0 && ic->ic_state == IEEE80211_S_RUN) | |
560 | bwfm_get_sta_info(sc, (struct ifmediareq *)data); | 560 | bwfm_get_sta_info(sc, (struct ifmediareq *)data); | |
561 | break; | 561 | break; | |
562 | 562 | |||
563 | default: | 563 | default: | |
564 | error = ieee80211_ioctl(ic, cmd, data); | 564 | error = ieee80211_ioctl(ic, cmd, data); | |
565 | } | 565 | } | |
566 | 566 | |||
567 | if (error == ENETRESET) { | 567 | if (error == ENETRESET) { | |
568 | if ((ifp->if_flags & IFF_UP) != 0 && | 568 | if ((ifp->if_flags & IFF_UP) != 0 && | |
569 | (ifp->if_flags & IFF_RUNNING) != 0 && | 569 | (ifp->if_flags & IFF_RUNNING) != 0 && | |
570 | ic->ic_roaming != IEEE80211_ROAMING_MANUAL) { | 570 | ic->ic_roaming != IEEE80211_ROAMING_MANUAL) { | |
571 | bwfm_init(ifp); | 571 | bwfm_init(ifp); | |
572 | } | 572 | } | |
573 | error = 0; | 573 | error = 0; | |
574 | } | 574 | } | |
575 | 575 | |||
576 | splx(s); | 576 | splx(s); | |
577 | 577 | |||
578 | return error; | 578 | return error; | |
579 | } | 579 | } | |
580 | 580 | |||
581 | int | 581 | int | |
582 | bwfm_send_mgmt(struct ieee80211com *ic, struct ieee80211_node *ni, | 582 | bwfm_send_mgmt(struct ieee80211com *ic, struct ieee80211_node *ni, | |
583 | int type, int arg) | 583 | int type, int arg) | |
584 | { | 584 | { | |
585 | return 0; | 585 | return 0; | |
586 | } | 586 | } | |
587 | 587 | |||
588 | void | 588 | void | |
589 | bwfm_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0, | 589 | bwfm_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0, | |
590 | struct ieee80211_node *ni, int subtype, int rssi, uint32_t rstamp) | 590 | struct ieee80211_node *ni, int subtype, int rssi, uint32_t rstamp) | |
591 | { | 591 | { | |
592 | } | 592 | } | |
593 | 593 | |||
594 | int | 594 | int | |
595 | bwfm_key_set(struct ieee80211com *ic, const struct ieee80211_key *wk, | 595 | bwfm_key_set(struct ieee80211com *ic, const struct ieee80211_key *wk, | |
596 | const uint8_t mac[IEEE80211_ADDR_LEN]) | 596 | const uint8_t mac[IEEE80211_ADDR_LEN]) | |
597 | { | 597 | { | |
598 | struct bwfm_softc *sc = ic->ic_ifp->if_softc; | 598 | struct bwfm_softc *sc = ic->ic_ifp->if_softc; | |
599 | struct bwfm_task *t; | 599 | struct bwfm_task *t; | |
600 | 600 | |||
601 | t = pcq_get(sc->sc_freetask); | 601 | t = pcq_get(sc->sc_freetask); | |
602 | if (t == NULL) { | 602 | if (t == NULL) { | |
603 | printf("%s: no free tasks\n", DEVNAME(sc)); | 603 | printf("%s: no free tasks\n", DEVNAME(sc)); | |
604 | return 0; | 604 | return 0; | |
605 | } | 605 | } | |
606 | 606 | |||
607 | t->t_cmd = BWFM_TASK_KEY_SET; | 607 | t->t_cmd = BWFM_TASK_KEY_SET; | |
608 | t->t_key.key = wk; | 608 | t->t_key.key = wk; | |
609 | memcpy(t->t_key.mac, mac, sizeof(t->t_key.mac)); | 609 | memcpy(t->t_key.mac, mac, sizeof(t->t_key.mac)); | |
610 | workqueue_enqueue(sc->sc_taskq, (struct work *)t, NULL); | 610 | workqueue_enqueue(sc->sc_taskq, (struct work *)t, NULL); | |
611 | return 1; | 611 | return 1; | |
612 | } | 612 | } | |
613 | 613 | |||
614 | static void | 614 | static void | |
615 | bwfm_key_set_cb(struct bwfm_softc *sc, struct bwfm_cmd_key *ck) | 615 | bwfm_key_set_cb(struct bwfm_softc *sc, struct bwfm_cmd_key *ck) | |
616 | { | 616 | { | |
617 | const struct ieee80211_key *wk = ck->key; | 617 | const struct ieee80211_key *wk = ck->key; | |
618 | const uint8_t *mac = ck->mac; | 618 | const uint8_t *mac = ck->mac; | |
619 | struct bwfm_wsec_key wsec_key; | 619 | struct bwfm_wsec_key wsec_key; | |
620 | uint32_t wsec_enable, wsec; | 620 | uint32_t wsec_enable, wsec; | |
621 | bool ext_key; | 621 | bool ext_key; | |
622 | 622 | |||
623 | #ifdef BWFM_DEBUG | 623 | #ifdef BWFM_DEBUG | |
624 | printf("key_set: key cipher %s len %d: ", wk->wk_cipher->ic_name, wk->wk_keylen); | 624 | printf("key_set: key cipher %s len %d: ", wk->wk_cipher->ic_name, wk->wk_keylen); | |
625 | for (int j = 0; j < sizeof(wk->wk_key); j++) | 625 | for (int j = 0; j < sizeof(wk->wk_key); j++) | |
626 | printf("%02x", wk->wk_key[j]); | 626 | printf("%02x", wk->wk_key[j]); | |
627 | #endif | 627 | #endif | |
628 | 628 | |||
629 | if ((wk->wk_flags & IEEE80211_KEY_GROUP) == 0 && | 629 | if ((wk->wk_flags & IEEE80211_KEY_GROUP) == 0 && | |
630 | wk->wk_cipher->ic_cipher != IEEE80211_CIPHER_WEP) { | 630 | wk->wk_cipher->ic_cipher != IEEE80211_CIPHER_WEP) { | |
631 | ext_key = true; | 631 | ext_key = true; | |
632 | } else { | 632 | } else { | |
633 | ext_key = false; | 633 | ext_key = false; | |
634 | } | 634 | } | |
635 | 635 | |||
636 | #ifdef BWFM_DEBUG | 636 | #ifdef BWFM_DEBUG | |
637 | printf(", ext_key = %d", ext_key); | 637 | printf(", ext_key = %d", ext_key); | |
638 | printf(", mac = %02x:%02x:%02x:%02x:%02x:%02x", | 638 | printf(", mac = %02x:%02x:%02x:%02x:%02x:%02x", | |
639 | mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); | 639 | mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); | |
640 | printf("\n"); | 640 | printf("\n"); | |
641 | #endif | 641 | #endif | |
642 | 642 | |||
643 | memset(&wsec_key, 0, sizeof(wsec_key)); | 643 | memset(&wsec_key, 0, sizeof(wsec_key)); | |
644 | if (ext_key && !IEEE80211_IS_MULTICAST(mac)) | 644 | if (ext_key && !IEEE80211_IS_MULTICAST(mac)) | |
645 | memcpy(wsec_key.ea, mac, sizeof(wsec_key.ea)); | 645 | memcpy(wsec_key.ea, mac, sizeof(wsec_key.ea)); | |
646 | wsec_key.index = htole32(wk->wk_keyix); | 646 | wsec_key.index = htole32(wk->wk_keyix); | |
647 | wsec_key.len = htole32(wk->wk_keylen); | 647 | wsec_key.len = htole32(wk->wk_keylen); | |
648 | memcpy(wsec_key.data, wk->wk_key, sizeof(wsec_key.data)); | 648 | memcpy(wsec_key.data, wk->wk_key, sizeof(wsec_key.data)); | |
649 | if (!ext_key) | 649 | if (!ext_key) | |
650 | wsec_key.flags = htole32(BWFM_WSEC_PRIMARY_KEY); | 650 | wsec_key.flags = htole32(BWFM_WSEC_PRIMARY_KEY); | |
651 | 651 | |||
652 | switch (wk->wk_cipher->ic_cipher) { | 652 | switch (wk->wk_cipher->ic_cipher) { | |
653 | case IEEE80211_CIPHER_WEP: | 653 | case IEEE80211_CIPHER_WEP: | |
654 | if (wk->wk_keylen == 5) | 654 | if (wk->wk_keylen == 5) | |
655 | wsec_key.algo = htole32(BWFM_CRYPTO_ALGO_WEP1); | 655 | wsec_key.algo = htole32(BWFM_CRYPTO_ALGO_WEP1); | |
656 | else if (wk->wk_keylen == 13) | 656 | else if (wk->wk_keylen == 13) | |
657 | wsec_key.algo = htole32(BWFM_CRYPTO_ALGO_WEP128); | 657 | wsec_key.algo = htole32(BWFM_CRYPTO_ALGO_WEP128); | |
658 | else | 658 | else | |
659 | return; | 659 | return; | |
660 | wsec_enable = BWFM_WSEC_WEP; | 660 | wsec_enable = BWFM_WSEC_WEP; | |
661 | break; | 661 | break; | |
662 | case IEEE80211_CIPHER_TKIP: | 662 | case IEEE80211_CIPHER_TKIP: | |
663 | wsec_key.algo = htole32(BWFM_CRYPTO_ALGO_TKIP); | 663 | wsec_key.algo = htole32(BWFM_CRYPTO_ALGO_TKIP); | |
664 | wsec_enable = BWFM_WSEC_TKIP; | 664 | wsec_enable = BWFM_WSEC_TKIP; | |
665 | break; | 665 | break; | |
666 | case IEEE80211_CIPHER_AES_CCM: | 666 | case IEEE80211_CIPHER_AES_CCM: | |
667 | wsec_key.algo = htole32(BWFM_CRYPTO_ALGO_AES_CCM); | 667 | wsec_key.algo = htole32(BWFM_CRYPTO_ALGO_AES_CCM); | |
668 | wsec_enable = BWFM_WSEC_AES; | 668 | wsec_enable = BWFM_WSEC_AES; | |
669 | break; | 669 | break; | |
670 | default: | 670 | default: | |
671 | printf("%s: %s: cipher %s not supported\n", DEVNAME(sc), | 671 | printf("%s: %s: cipher %s not supported\n", DEVNAME(sc), | |
672 | __func__, wk->wk_cipher->ic_name); | 672 | __func__, wk->wk_cipher->ic_name); | |
673 | return; | 673 | return; | |
674 | } | 674 | } | |
675 | 675 | |||
676 | if (bwfm_fwvar_var_set_data(sc, "wsec_key", &wsec_key, sizeof(wsec_key))) | 676 | if (bwfm_fwvar_var_set_data(sc, "wsec_key", &wsec_key, sizeof(wsec_key))) | |
677 | return; | 677 | return; | |
678 | 678 | |||
679 | bwfm_fwvar_var_set_int(sc, "wpa_auth", BWFM_WPA_AUTH_WPA2_PSK); | 679 | bwfm_fwvar_var_set_int(sc, "wpa_auth", BWFM_WPA_AUTH_WPA2_PSK); | |
680 | 680 | |||
681 | bwfm_fwvar_var_get_int(sc, "wsec", &wsec); | 681 | bwfm_fwvar_var_get_int(sc, "wsec", &wsec); | |
682 | wsec |= wsec_enable; | 682 | wsec |= wsec_enable; | |
683 | bwfm_fwvar_var_set_int(sc, "wsec", wsec); | 683 | bwfm_fwvar_var_set_int(sc, "wsec", wsec); | |
684 | } | 684 | } | |
685 | 685 | |||
686 | int | 686 | int | |
687 | bwfm_key_delete(struct ieee80211com *ic, const struct ieee80211_key *wk) | 687 | bwfm_key_delete(struct ieee80211com *ic, const struct ieee80211_key *wk) | |
688 | { | 688 | { | |
689 | struct bwfm_softc *sc = ic->ic_ifp->if_softc; | 689 | struct bwfm_softc *sc = ic->ic_ifp->if_softc; | |
690 | struct bwfm_task *t; | 690 | struct bwfm_task *t; | |
691 | 691 | |||
692 | t = pcq_get(sc->sc_freetask); | 692 | t = pcq_get(sc->sc_freetask); | |
693 | if (t == NULL) { | 693 | if (t == NULL) { | |
694 | printf("%s: no free tasks\n", DEVNAME(sc)); | 694 | printf("%s: no free tasks\n", DEVNAME(sc)); | |
695 | return 0; | 695 | return 0; | |
696 | } | 696 | } | |
697 | 697 | |||
698 | t->t_cmd = BWFM_TASK_KEY_DELETE; | 698 | t->t_cmd = BWFM_TASK_KEY_DELETE; | |
699 | t->t_key.key = wk; | 699 | t->t_key.key = wk; | |
700 | memset(t->t_key.mac, 0, sizeof(t->t_key.mac)); | 700 | memset(t->t_key.mac, 0, sizeof(t->t_key.mac)); | |
701 | workqueue_enqueue(sc->sc_taskq, (struct work *)t, NULL); | 701 | workqueue_enqueue(sc->sc_taskq, (struct work *)t, NULL); | |
702 | 702 | |||
703 | return 1; | 703 | return 1; | |
704 | } | 704 | } | |
705 | 705 | |||
706 | static void | 706 | static void | |
707 | bwfm_key_delete_cb(struct bwfm_softc *sc, struct bwfm_cmd_key *ck) | 707 | bwfm_key_delete_cb(struct bwfm_softc *sc, struct bwfm_cmd_key *ck) | |
708 | { | 708 | { | |
709 | const struct ieee80211_key *wk = ck->key; | 709 | const struct ieee80211_key *wk = ck->key; | |
710 | struct bwfm_wsec_key wsec_key; | 710 | struct bwfm_wsec_key wsec_key; | |
711 | 711 | |||
712 | memset(&wsec_key, 0, sizeof(wsec_key)); | 712 | memset(&wsec_key, 0, sizeof(wsec_key)); | |
713 | wsec_key.index = htole32(wk->wk_keyix); | 713 | wsec_key.index = htole32(wk->wk_keyix); | |
714 | wsec_key.flags = htole32(BWFM_WSEC_PRIMARY_KEY); | 714 | wsec_key.flags = htole32(BWFM_WSEC_PRIMARY_KEY); | |
715 | 715 | |||
716 | if (bwfm_fwvar_var_set_data(sc, "wsec_key", &wsec_key, sizeof(wsec_key))) | 716 | if (bwfm_fwvar_var_set_data(sc, "wsec_key", &wsec_key, sizeof(wsec_key))) | |
717 | return; | 717 | return; | |
718 | } | 718 | } | |
719 | 719 | |||
720 | int | 720 | int | |
721 | bwfm_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg) | 721 | bwfm_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg) | |
722 | { | 722 | { | |
723 | struct bwfm_softc *sc = ic->ic_ifp->if_softc; | 723 | struct bwfm_softc *sc = ic->ic_ifp->if_softc; | |
724 | struct bwfm_task *t; | 724 | struct bwfm_task *t; | |
725 | 725 | |||
726 | t = pcq_get(sc->sc_freetask); | 726 | t = pcq_get(sc->sc_freetask); | |
727 | if (t == NULL) { | 727 | if (t == NULL) { | |
728 | printf("%s: no free tasks\n", DEVNAME(sc)); | 728 | printf("%s: no free tasks\n", DEVNAME(sc)); | |
729 | return EIO; | 729 | return EIO; | |
730 | } | 730 | } | |
731 | 731 | |||
732 | t->t_cmd = BWFM_TASK_NEWSTATE; | 732 | t->t_cmd = BWFM_TASK_NEWSTATE; | |
733 | t->t_newstate.state = nstate; | 733 | t->t_newstate.state = nstate; | |
734 | t->t_newstate.arg = arg; | 734 | t->t_newstate.arg = arg; | |
735 | workqueue_enqueue(sc->sc_taskq, (struct work *)t, NULL); | 735 | workqueue_enqueue(sc->sc_taskq, (struct work *)t, NULL); | |
736 | 736 | |||
737 | return 0; | 737 | return 0; | |
738 | } | 738 | } | |
739 | 739 | |||
740 | void | 740 | void | |
741 | bwfm_newstate_cb(struct bwfm_softc *sc, struct bwfm_cmd_newstate *cmd) | 741 | bwfm_newstate_cb(struct bwfm_softc *sc, struct bwfm_cmd_newstate *cmd) | |
742 | { | 742 | { | |
743 | struct ieee80211com *ic = &sc->sc_ic; | 743 | struct ieee80211com *ic = &sc->sc_ic; | |
744 | enum ieee80211_state ostate = ic->ic_state; | 744 | enum ieee80211_state ostate = ic->ic_state; | |
745 | enum ieee80211_state nstate = cmd->state; | 745 | enum ieee80211_state nstate = cmd->state; | |
746 | int s; | 746 | int s; | |
747 | 747 | |||
748 | DPRINTF(("%s: newstate %d -> %d\n", DEVNAME(sc), ostate, nstate)); | 748 | DPRINTF(("%s: newstate %d -> %d\n", DEVNAME(sc), ostate, nstate)); | |
749 | 749 | |||
750 | s = splnet(); | 750 | s = splnet(); | |
751 | 751 | |||
752 | switch (nstate) { | 752 | switch (nstate) { | |
753 | case IEEE80211_S_INIT: | 753 | case IEEE80211_S_INIT: | |
754 | break; | 754 | break; | |
755 | 755 | |||
756 | case IEEE80211_S_SCAN: | 756 | case IEEE80211_S_SCAN: | |
757 | if (ostate != IEEE80211_S_SCAN) { | 757 | if (ostate != IEEE80211_S_SCAN) { | |
758 | /* Start of scanning */ | 758 | /* Start of scanning */ | |
759 | bwfm_scan(sc); | 759 | bwfm_scan(sc); | |
760 | } | 760 | } | |
761 | break; | 761 | break; | |
762 | 762 | |||
763 | case IEEE80211_S_AUTH: | 763 | case IEEE80211_S_AUTH: | |
764 | bwfm_connect(sc); | 764 | bwfm_connect(sc); | |
765 | break; | 765 | break; | |
766 | 766 | |||
767 | case IEEE80211_S_ASSOC: | 767 | case IEEE80211_S_ASSOC: | |
768 | break; | 768 | break; | |
769 | 769 | |||
770 | case IEEE80211_S_RUN: | 770 | case IEEE80211_S_RUN: | |
771 | break; | 771 | break; | |
772 | } | 772 | } | |
773 | 773 | |||
774 | sc->sc_newstate(ic, nstate, cmd->arg); | 774 | sc->sc_newstate(ic, nstate, cmd->arg); | |
775 | 775 | |||
776 | splx(s); | 776 | splx(s); | |
777 | } | 777 | } | |
778 | 778 | |||
779 | void | 779 | void | |
780 | bwfm_newassoc(struct ieee80211_node *ni, int isnew) | 780 | bwfm_newassoc(struct ieee80211_node *ni, int isnew) | |
781 | { | 781 | { | |
782 | /* Firmware handles rate adaptation for us */ | 782 | /* Firmware handles rate adaptation for us */ | |
783 | ni->ni_txrate = 0; | 783 | ni->ni_txrate = 0; | |
784 | } | 784 | } | |
785 | 785 | |||
786 | void | 786 | void | |
787 | bwfm_task(struct work *wk, void *arg) | 787 | bwfm_task(struct work *wk, void *arg) | |
788 | { | 788 | { | |
789 | struct bwfm_task *t = (struct bwfm_task *)wk; | 789 | struct bwfm_task *t = (struct bwfm_task *)wk; | |
790 | struct bwfm_softc *sc = t->t_sc; | 790 | struct bwfm_softc *sc = t->t_sc; | |
791 | 791 | |||
792 | switch (t->t_cmd) { | 792 | switch (t->t_cmd) { | |
793 | case BWFM_TASK_NEWSTATE: | 793 | case BWFM_TASK_NEWSTATE: | |
794 | bwfm_newstate_cb(sc, &t->t_newstate); | 794 | bwfm_newstate_cb(sc, &t->t_newstate); | |
795 | break; | 795 | break; | |
796 | case BWFM_TASK_KEY_SET: | 796 | case BWFM_TASK_KEY_SET: | |
797 | bwfm_key_set_cb(sc, &t->t_key); | 797 | bwfm_key_set_cb(sc, &t->t_key); | |
798 | break; | 798 | break; | |
799 | case BWFM_TASK_KEY_DELETE: | 799 | case BWFM_TASK_KEY_DELETE: | |
800 | bwfm_key_delete_cb(sc, &t->t_key); | 800 | bwfm_key_delete_cb(sc, &t->t_key); | |
801 | break; | 801 | break; | |
802 | case BWFM_TASK_RX_EVENT: | 802 | case BWFM_TASK_RX_EVENT: | |
803 | bwfm_rx_event_cb(sc, t->t_mbuf); | 803 | bwfm_rx_event_cb(sc, t->t_mbuf); | |
804 | break; | 804 | break; | |
805 | default: | 805 | default: | |
806 | panic("bwfm: unknown task command %d", t->t_cmd); | 806 | panic("bwfm: unknown task command %d", t->t_cmd); | |
807 | } | 807 | } | |
808 | 808 | |||
809 | pcq_put(sc->sc_freetask, t); | 809 | pcq_put(sc->sc_freetask, t); | |
810 | } | 810 | } | |
811 | 811 | |||
812 | int | 812 | int | |
813 | bwfm_media_change(struct ifnet *ifp) | 813 | bwfm_media_change(struct ifnet *ifp) | |
814 | { | 814 | { | |
815 | return 0; | 815 | return 0; | |
816 | } | 816 | } | |
817 | 817 | |||
818 | /* Chip initialization (SDIO, PCIe) */ | 818 | /* Chip initialization (SDIO, PCIe) */ | |
819 | int | 819 | int | |
820 | bwfm_chip_attach(struct bwfm_softc *sc) | 820 | bwfm_chip_attach(struct bwfm_softc *sc) | |
821 | { | 821 | { | |
822 | struct bwfm_core *core; | 822 | struct bwfm_core *core; | |
823 | int need_socram = 0; | 823 | int need_socram = 0; | |
824 | int has_socram = 0; | 824 | int has_socram = 0; | |
825 | int cpu_found = 0; | 825 | int cpu_found = 0; | |
826 | uint32_t val; | 826 | uint32_t val; | |
827 | 827 | |||
828 | LIST_INIT(&sc->sc_chip.ch_list); | 828 | LIST_INIT(&sc->sc_chip.ch_list); | |
829 | 829 | |||
830 | if (sc->sc_buscore_ops->bc_prepare(sc) != 0) { | 830 | if (sc->sc_buscore_ops->bc_prepare(sc) != 0) { | |
831 | printf("%s: failed buscore prepare\n", DEVNAME(sc)); | 831 | printf("%s: failed buscore prepare\n", DEVNAME(sc)); | |
832 | return 1; | 832 | return 1; | |
833 | } | 833 | } | |
834 | 834 | |||
835 | val = sc->sc_buscore_ops->bc_read(sc, | 835 | val = sc->sc_buscore_ops->bc_read(sc, | |
836 | BWFM_CHIP_BASE + BWFM_CHIP_REG_CHIPID); | 836 | BWFM_CHIP_BASE + BWFM_CHIP_REG_CHIPID); | |
837 | sc->sc_chip.ch_chip = BWFM_CHIP_CHIPID_ID(val); | 837 | sc->sc_chip.ch_chip = BWFM_CHIP_CHIPID_ID(val); | |
838 | sc->sc_chip.ch_chiprev = BWFM_CHIP_CHIPID_REV(val); | 838 | sc->sc_chip.ch_chiprev = BWFM_CHIP_CHIPID_REV(val); | |
839 | 839 | |||
840 | if ((sc->sc_chip.ch_chip > 0xa000) || (sc->sc_chip.ch_chip < 0x4000)) | 840 | if ((sc->sc_chip.ch_chip > 0xa000) || (sc->sc_chip.ch_chip < 0x4000)) | |
841 | snprintf(sc->sc_chip.ch_name, sizeof(sc->sc_chip.ch_name), | 841 | snprintf(sc->sc_chip.ch_name, sizeof(sc->sc_chip.ch_name), | |
842 | "%d", sc->sc_chip.ch_chip); | 842 | "%d", sc->sc_chip.ch_chip); | |
843 | else | 843 | else | |
844 | snprintf(sc->sc_chip.ch_name, sizeof(sc->sc_chip.ch_name), | 844 | snprintf(sc->sc_chip.ch_name, sizeof(sc->sc_chip.ch_name), | |
845 | "%x", sc->sc_chip.ch_chip); | 845 | "%x", sc->sc_chip.ch_chip); | |
846 | 846 | |||
847 | switch (BWFM_CHIP_CHIPID_TYPE(val)) | 847 | switch (BWFM_CHIP_CHIPID_TYPE(val)) | |
848 | { | 848 | { | |
849 | case BWFM_CHIP_CHIPID_TYPE_SOCI_SB: | 849 | case BWFM_CHIP_CHIPID_TYPE_SOCI_SB: | |
850 | printf("%s: SoC interconnect SB not implemented\n", | 850 | printf("%s: SoC interconnect SB not implemented\n", | |
851 | DEVNAME(sc)); | 851 | DEVNAME(sc)); | |
852 | return 1; | 852 | return 1; | |
853 | case BWFM_CHIP_CHIPID_TYPE_SOCI_AI: | 853 | case BWFM_CHIP_CHIPID_TYPE_SOCI_AI: | |
854 | sc->sc_chip.ch_core_isup = bwfm_chip_ai_isup; | 854 | sc->sc_chip.ch_core_isup = bwfm_chip_ai_isup; | |
855 | sc->sc_chip.ch_core_disable = bwfm_chip_ai_disable; | 855 | sc->sc_chip.ch_core_disable = bwfm_chip_ai_disable; | |
856 | sc->sc_chip.ch_core_reset = bwfm_chip_ai_reset; | 856 | sc->sc_chip.ch_core_reset = bwfm_chip_ai_reset; | |
857 | bwfm_chip_dmp_erom_scan(sc); | 857 | bwfm_chip_dmp_erom_scan(sc); | |
858 | break; | 858 | break; | |
859 | default: | 859 | default: | |
860 | printf("%s: SoC interconnect %d unknown\n", | 860 | printf("%s: SoC interconnect %d unknown\n", | |
861 | DEVNAME(sc), BWFM_CHIP_CHIPID_TYPE(val)); | 861 | DEVNAME(sc), BWFM_CHIP_CHIPID_TYPE(val)); | |
862 | return 1; | 862 | return 1; | |
863 | } | 863 | } | |
864 | 864 | |||
865 | LIST_FOREACH(core, &sc->sc_chip.ch_list, co_link) { | 865 | LIST_FOREACH(core, &sc->sc_chip.ch_list, co_link) { | |
866 | DPRINTF(("%s: 0x%x:%-2d base 0x%08x wrap 0x%08x\n", | 866 | DPRINTF(("%s: 0x%x:%-2d base 0x%08x wrap 0x%08x\n", | |
867 | DEVNAME(sc), core->co_id, core->co_rev, | 867 | DEVNAME(sc), core->co_id, core->co_rev, | |
868 | core->co_base, core->co_wrapbase)); | 868 | core->co_base, core->co_wrapbase)); | |
869 | 869 | |||
870 | switch (core->co_id) { | 870 | switch (core->co_id) { | |
871 | case BWFM_AGENT_CORE_ARM_CM3: | 871 | case BWFM_AGENT_CORE_ARM_CM3: | |
872 | need_socram = true; | 872 | need_socram = true; | |
873 | /* FALLTHROUGH */ | 873 | /* FALLTHROUGH */ | |
874 | case BWFM_AGENT_CORE_ARM_CR4: | 874 | case BWFM_AGENT_CORE_ARM_CR4: | |
875 | case BWFM_AGENT_CORE_ARM_CA7: | 875 | case BWFM_AGENT_CORE_ARM_CA7: | |
876 | cpu_found = true; | 876 | cpu_found = true; | |
877 | break; | 877 | break; | |
878 | case BWFM_AGENT_INTERNAL_MEM: | 878 | case BWFM_AGENT_INTERNAL_MEM: | |
879 | has_socram = true; | 879 | has_socram = true; | |
880 | break; | 880 | break; | |
881 | default: | 881 | default: | |
882 | break; | 882 | break; | |
883 | } | 883 | } | |
884 | } | 884 | } | |
885 | 885 | |||
886 | if (!cpu_found) { | 886 | if (!cpu_found) { | |
887 | printf("%s: CPU core not detected\n", DEVNAME(sc)); | 887 | printf("%s: CPU core not detected\n", DEVNAME(sc)); | |
888 | return 1; | 888 | return 1; | |
889 | } | 889 | } | |
890 | if (need_socram && !has_socram) { | 890 | if (need_socram && !has_socram) { | |
891 | printf("%s: RAM core not provided\n", DEVNAME(sc)); | 891 | printf("%s: RAM core not provided\n", DEVNAME(sc)); | |
892 | return 1; | 892 | return 1; | |
893 | } | 893 | } | |
894 | 894 | |||
895 | bwfm_chip_set_passive(sc); | 895 | bwfm_chip_set_passive(sc); | |
896 | 896 | |||
897 | if (sc->sc_buscore_ops->bc_reset) { | 897 | if (sc->sc_buscore_ops->bc_reset) { | |
898 | sc->sc_buscore_ops->bc_reset(sc); | 898 | sc->sc_buscore_ops->bc_reset(sc); | |
899 | bwfm_chip_set_passive(sc); | 899 | bwfm_chip_set_passive(sc); | |
900 | } | 900 | } | |
901 | 901 | |||
902 | if ((core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CR4)) != NULL) { | 902 | if ((core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CR4)) != NULL) { | |
903 | bwfm_chip_tcm_ramsize(sc, core); | 903 | bwfm_chip_tcm_ramsize(sc, core); | |
904 | bwfm_chip_tcm_rambase(sc); | 904 | bwfm_chip_tcm_rambase(sc); | |
905 | } else if ((core = bwfm_chip_get_core(sc, BWFM_AGENT_SYS_MEM)) != NULL) { | 905 | } else if ((core = bwfm_chip_get_core(sc, BWFM_AGENT_SYS_MEM)) != NULL) { | |
906 | bwfm_chip_sysmem_ramsize(sc, core); | 906 | bwfm_chip_sysmem_ramsize(sc, core); | |
907 | bwfm_chip_tcm_rambase(sc); | 907 | bwfm_chip_tcm_rambase(sc); | |
908 | } else if ((core = bwfm_chip_get_core(sc, BWFM_AGENT_INTERNAL_MEM)) != NULL) { | 908 | } else if ((core = bwfm_chip_get_core(sc, BWFM_AGENT_INTERNAL_MEM)) != NULL) { | |
909 | bwfm_chip_socram_ramsize(sc, core); | 909 | bwfm_chip_socram_ramsize(sc, core); | |
910 | } | 910 | } | |
911 | 911 | |||
912 | core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_CHIPCOMMON); | 912 | core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_CHIPCOMMON); | |
913 | sc->sc_chip.ch_cc_caps = sc->sc_buscore_ops->bc_read(sc, | 913 | sc->sc_chip.ch_cc_caps = sc->sc_buscore_ops->bc_read(sc, | |
914 | core->co_base + BWFM_CHIP_REG_CAPABILITIES); | 914 | core->co_base + BWFM_CHIP_REG_CAPABILITIES); | |
915 | sc->sc_chip.ch_cc_caps_ext = sc->sc_buscore_ops->bc_read(sc, | 915 | sc->sc_chip.ch_cc_caps_ext = sc->sc_buscore_ops->bc_read(sc, | |
916 | core->co_base + BWFM_CHIP_REG_CAPABILITIES_EXT); | 916 | core->co_base + BWFM_CHIP_REG_CAPABILITIES_EXT); | |
917 | 917 | |||
918 | core = bwfm_chip_get_pmu(sc); | 918 | core = bwfm_chip_get_pmu(sc); | |
919 | if (sc->sc_chip.ch_cc_caps & BWFM_CHIP_REG_CAPABILITIES_PMU) { | 919 | if (sc->sc_chip.ch_cc_caps & BWFM_CHIP_REG_CAPABILITIES_PMU) { | |
920 | sc->sc_chip.ch_pmucaps = sc->sc_buscore_ops->bc_read(sc, | 920 | sc->sc_chip.ch_pmucaps = sc->sc_buscore_ops->bc_read(sc, | |
921 | core->co_base + BWFM_CHIP_REG_PMUCAPABILITIES); | 921 | core->co_base + BWFM_CHIP_REG_PMUCAPABILITIES); | |
922 | sc->sc_chip.ch_pmurev = sc->sc_chip.ch_pmucaps & | 922 | sc->sc_chip.ch_pmurev = sc->sc_chip.ch_pmucaps & | |
923 | BWFM_CHIP_REG_PMUCAPABILITIES_REV_MASK; | 923 | BWFM_CHIP_REG_PMUCAPABILITIES_REV_MASK; | |
924 | } | 924 | } | |
925 | 925 | |||
926 | if (sc->sc_buscore_ops->bc_setup) | 926 | if (sc->sc_buscore_ops->bc_setup) | |
927 | sc->sc_buscore_ops->bc_setup(sc); | 927 | sc->sc_buscore_ops->bc_setup(sc); | |
928 | 928 | |||
929 | return 0; | 929 | return 0; | |
930 | } | 930 | } | |
931 | 931 | |||
932 | struct bwfm_core * | 932 | struct bwfm_core * | |
933 | bwfm_chip_get_core(struct bwfm_softc *sc, int id) | 933 | bwfm_chip_get_core(struct bwfm_softc *sc, int id) | |
934 | { | 934 | { | |
935 | struct bwfm_core *core; | 935 | struct bwfm_core *core; | |
936 | 936 | |||
937 | LIST_FOREACH(core, &sc->sc_chip.ch_list, co_link) { | 937 | LIST_FOREACH(core, &sc->sc_chip.ch_list, co_link) { | |
938 | if (core->co_id == id) | 938 | if (core->co_id == id) | |
939 | return core; | 939 | return core; | |
940 | } | 940 | } | |
941 | 941 | |||
942 | return NULL; | 942 | return NULL; | |
943 | } | 943 | } | |
944 | 944 | |||
945 | struct bwfm_core * | 945 | struct bwfm_core * | |
946 | bwfm_chip_get_pmu(struct bwfm_softc *sc) | 946 | bwfm_chip_get_pmu(struct bwfm_softc *sc) | |
947 | { | 947 | { | |
948 | struct bwfm_core *cc, *pmu; | 948 | struct bwfm_core *cc, *pmu; | |
949 | 949 | |||
950 | cc = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_CHIPCOMMON); | 950 | cc = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_CHIPCOMMON); | |
951 | if (cc->co_rev >= 35 && sc->sc_chip.ch_cc_caps_ext & | 951 | if (cc->co_rev >= 35 && sc->sc_chip.ch_cc_caps_ext & | |
952 | BWFM_CHIP_REG_CAPABILITIES_EXT_AOB_PRESENT) { | 952 | BWFM_CHIP_REG_CAPABILITIES_EXT_AOB_PRESENT) { | |
953 | pmu = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_PMU); | 953 | pmu = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_PMU); | |
954 | if (pmu) | 954 | if (pmu) | |
955 | return pmu; | 955 | return pmu; | |
956 | } | 956 | } | |
957 | 957 | |||
958 | return cc; | 958 | return cc; | |
959 | } | 959 | } | |
960 | 960 | |||
961 | /* Functions for the AI interconnect */ | 961 | /* Functions for the AI interconnect */ | |
962 | int | 962 | int | |
963 | bwfm_chip_ai_isup(struct bwfm_softc *sc, struct bwfm_core *core) | 963 | bwfm_chip_ai_isup(struct bwfm_softc *sc, struct bwfm_core *core) | |
964 | { | 964 | { | |
965 | uint32_t ioctl, reset; | 965 | uint32_t ioctl, reset; | |
966 | 966 | |||
967 | ioctl = sc->sc_buscore_ops->bc_read(sc, | 967 | ioctl = sc->sc_buscore_ops->bc_read(sc, | |
968 | core->co_wrapbase + BWFM_AGENT_IOCTL); | 968 | core->co_wrapbase + BWFM_AGENT_IOCTL); | |
969 | reset = sc->sc_buscore_ops->bc_read(sc, | 969 | reset = sc->sc_buscore_ops->bc_read(sc, | |
970 | core->co_wrapbase + BWFM_AGENT_RESET_CTL); | 970 | core->co_wrapbase + BWFM_AGENT_RESET_CTL); | |
971 | 971 | |||
972 | if (((ioctl & (BWFM_AGENT_IOCTL_FGC | BWFM_AGENT_IOCTL_CLK)) == | 972 | if (((ioctl & (BWFM_AGENT_IOCTL_FGC | BWFM_AGENT_IOCTL_CLK)) == | |
973 | BWFM_AGENT_IOCTL_CLK) && | 973 | BWFM_AGENT_IOCTL_CLK) && | |
974 | ((reset & BWFM_AGENT_RESET_CTL_RESET) == 0)) | 974 | ((reset & BWFM_AGENT_RESET_CTL_RESET) == 0)) | |
975 | return 1; | 975 | return 1; | |
976 | 976 | |||
977 | return 0; | 977 | return 0; | |
978 | } | 978 | } | |
979 | 979 | |||
980 | void | 980 | void | |
981 | bwfm_chip_ai_disable(struct bwfm_softc *sc, struct bwfm_core *core, | 981 | bwfm_chip_ai_disable(struct bwfm_softc *sc, struct bwfm_core *core, | |
982 | uint32_t prereset, uint32_t reset) | 982 | uint32_t prereset, uint32_t reset) | |
983 | { | 983 | { | |
984 | uint32_t val; | 984 | uint32_t val; | |
985 | int i; | 985 | int i; | |
986 | 986 | |||
987 | val = sc->sc_buscore_ops->bc_read(sc, | 987 | val = sc->sc_buscore_ops->bc_read(sc, | |
988 | core->co_wrapbase + BWFM_AGENT_RESET_CTL); | 988 | core->co_wrapbase + BWFM_AGENT_RESET_CTL); | |
989 | if ((val & BWFM_AGENT_RESET_CTL_RESET) == 0) { | 989 | if ((val & BWFM_AGENT_RESET_CTL_RESET) == 0) { | |
990 | 990 | |||
991 | sc->sc_buscore_ops->bc_write(sc, | 991 | sc->sc_buscore_ops->bc_write(sc, | |
992 | core->co_wrapbase + BWFM_AGENT_IOCTL, | 992 | core->co_wrapbase + BWFM_AGENT_IOCTL, | |
993 | prereset | BWFM_AGENT_IOCTL_FGC | BWFM_AGENT_IOCTL_CLK); | 993 | prereset | BWFM_AGENT_IOCTL_FGC | BWFM_AGENT_IOCTL_CLK); | |
994 | sc->sc_buscore_ops->bc_read(sc, | 994 | sc->sc_buscore_ops->bc_read(sc, | |
995 | core->co_wrapbase + BWFM_AGENT_IOCTL); | 995 | core->co_wrapbase + BWFM_AGENT_IOCTL); | |
996 | 996 | |||
997 | sc->sc_buscore_ops->bc_write(sc, | 997 | sc->sc_buscore_ops->bc_write(sc, | |
998 | core->co_wrapbase + BWFM_AGENT_RESET_CTL, | 998 | core->co_wrapbase + BWFM_AGENT_RESET_CTL, | |
999 | BWFM_AGENT_RESET_CTL_RESET); | 999 | BWFM_AGENT_RESET_CTL_RESET); | |
1000 | delay(20); | 1000 | delay(20); | |
1001 | 1001 | |||
1002 | for (i = 300; i > 0; i--) { | 1002 | for (i = 300; i > 0; i--) { | |
1003 | if (sc->sc_buscore_ops->bc_read(sc, | 1003 | if (sc->sc_buscore_ops->bc_read(sc, | |
1004 | core->co_wrapbase + BWFM_AGENT_RESET_CTL) == | 1004 | core->co_wrapbase + BWFM_AGENT_RESET_CTL) == | |
1005 | BWFM_AGENT_RESET_CTL_RESET) | 1005 | BWFM_AGENT_RESET_CTL_RESET) | |
1006 | break; | 1006 | break; | |
1007 | } | 1007 | } | |
1008 | if (i == 0) | 1008 | if (i == 0) | |
1009 | printf("%s: timeout on core reset\n", DEVNAME(sc)); | 1009 | printf("%s: timeout on core reset\n", DEVNAME(sc)); | |
1010 | } | 1010 | } | |
1011 | 1011 | |||
1012 | sc->sc_buscore_ops->bc_write(sc, | 1012 | sc->sc_buscore_ops->bc_write(sc, | |
1013 | core->co_wrapbase + BWFM_AGENT_IOCTL, | 1013 | core->co_wrapbase + BWFM_AGENT_IOCTL, | |
1014 | reset | BWFM_AGENT_IOCTL_FGC | BWFM_AGENT_IOCTL_CLK); | 1014 | reset | BWFM_AGENT_IOCTL_FGC | BWFM_AGENT_IOCTL_CLK); | |
1015 | sc->sc_buscore_ops->bc_read(sc, | 1015 | sc->sc_buscore_ops->bc_read(sc, | |
1016 | core->co_wrapbase + BWFM_AGENT_IOCTL); | 1016 | core->co_wrapbase + BWFM_AGENT_IOCTL); | |
1017 | } | 1017 | } | |
1018 | 1018 | |||
1019 | void | 1019 | void | |
1020 | bwfm_chip_ai_reset(struct bwfm_softc *sc, struct bwfm_core *core, | 1020 | bwfm_chip_ai_reset(struct bwfm_softc *sc, struct bwfm_core *core, | |
1021 | uint32_t prereset, uint32_t reset, uint32_t postreset) | 1021 | uint32_t prereset, uint32_t reset, uint32_t postreset) | |
1022 | { | 1022 | { | |
1023 | int i; | 1023 | int i; | |
1024 | 1024 | |||
1025 | bwfm_chip_ai_disable(sc, core, prereset, reset); | 1025 | bwfm_chip_ai_disable(sc, core, prereset, reset); | |
1026 | 1026 | |||
1027 | for (i = 50; i > 0; i--) { | 1027 | for (i = 50; i > 0; i--) { | |
1028 | if ((sc->sc_buscore_ops->bc_read(sc, | 1028 | if ((sc->sc_buscore_ops->bc_read(sc, | |
1029 | core->co_wrapbase + BWFM_AGENT_RESET_CTL) & | 1029 | core->co_wrapbase + BWFM_AGENT_RESET_CTL) & | |
1030 | BWFM_AGENT_RESET_CTL_RESET) == 0) | 1030 | BWFM_AGENT_RESET_CTL_RESET) == 0) | |
1031 | break; | 1031 | break; | |
1032 | sc->sc_buscore_ops->bc_write(sc, | 1032 | sc->sc_buscore_ops->bc_write(sc, | |
1033 | core->co_wrapbase + BWFM_AGENT_RESET_CTL, 0); | 1033 | core->co_wrapbase + BWFM_AGENT_RESET_CTL, 0); | |
1034 | delay(60); | 1034 | delay(60); | |
1035 | } | 1035 | } | |
1036 | if (i == 0) | 1036 | if (i == 0) | |
1037 | printf("%s: timeout on core reset\n", DEVNAME(sc)); | 1037 | printf("%s: timeout on core reset\n", DEVNAME(sc)); | |
1038 | 1038 | |||
1039 | sc->sc_buscore_ops->bc_write(sc, | 1039 | sc->sc_buscore_ops->bc_write(sc, | |
1040 | core->co_wrapbase + BWFM_AGENT_IOCTL, | 1040 | core->co_wrapbase + BWFM_AGENT_IOCTL, | |
1041 | postreset | BWFM_AGENT_IOCTL_CLK); | 1041 | postreset | BWFM_AGENT_IOCTL_CLK); | |
1042 | sc->sc_buscore_ops->bc_read(sc, | 1042 | sc->sc_buscore_ops->bc_read(sc, | |
1043 | core->co_wrapbase + BWFM_AGENT_IOCTL); | 1043 | core->co_wrapbase + BWFM_AGENT_IOCTL); | |
1044 | } | 1044 | } | |
1045 | 1045 | |||
1046 | void | 1046 | void | |
1047 | bwfm_chip_dmp_erom_scan(struct bwfm_softc *sc) | 1047 | bwfm_chip_dmp_erom_scan(struct bwfm_softc *sc) | |
1048 | { | 1048 | { | |
1049 | uint32_t erom, val, base, wrap; | 1049 | uint32_t erom, val, base, wrap; | |
1050 | uint8_t type = 0; | 1050 | uint8_t type = 0; | |
1051 | uint16_t id; | 1051 | uint16_t id; | |
1052 | uint8_t nmw, nsw, rev; | 1052 | uint8_t nmw, nsw, rev; | |
1053 | struct bwfm_core *core; | 1053 | struct bwfm_core *core; | |
1054 | 1054 | |||
1055 | erom = sc->sc_buscore_ops->bc_read(sc, | 1055 | erom = sc->sc_buscore_ops->bc_read(sc, | |
1056 | BWFM_CHIP_BASE + BWFM_CHIP_REG_EROMPTR); | 1056 | BWFM_CHIP_BASE + BWFM_CHIP_REG_EROMPTR); | |
1057 | while (type != BWFM_DMP_DESC_EOT) { | 1057 | while (type != BWFM_DMP_DESC_EOT) { | |
1058 | val = sc->sc_buscore_ops->bc_read(sc, erom); | 1058 | val = sc->sc_buscore_ops->bc_read(sc, erom); | |
1059 | type = val & BWFM_DMP_DESC_MASK; | 1059 | type = val & BWFM_DMP_DESC_MASK; | |
1060 | erom += 4; | 1060 | erom += 4; | |
1061 | 1061 | |||
1062 | if (type != BWFM_DMP_DESC_COMPONENT) | 1062 | if (type != BWFM_DMP_DESC_COMPONENT) | |
1063 | continue; | 1063 | continue; | |
1064 | 1064 | |||
1065 | id = (val & BWFM_DMP_COMP_PARTNUM) | 1065 | id = (val & BWFM_DMP_COMP_PARTNUM) | |
1066 | >> BWFM_DMP_COMP_PARTNUM_S; | 1066 | >> BWFM_DMP_COMP_PARTNUM_S; | |
1067 | 1067 | |||
1068 | val = sc->sc_buscore_ops->bc_read(sc, erom); | 1068 | val = sc->sc_buscore_ops->bc_read(sc, erom); | |
1069 | type = val & BWFM_DMP_DESC_MASK; | 1069 | type = val & BWFM_DMP_DESC_MASK; | |
1070 | erom += 4; | 1070 | erom += 4; | |
1071 | 1071 | |||
1072 | if (type != BWFM_DMP_DESC_COMPONENT) { | 1072 | if (type != BWFM_DMP_DESC_COMPONENT) { | |
1073 | printf("%s: not component descriptor\n", DEVNAME(sc)); | 1073 | printf("%s: not component descriptor\n", DEVNAME(sc)); | |
1074 | return; | 1074 | return; | |
1075 | } | 1075 | } | |
1076 | 1076 | |||
1077 | nmw = (val & BWFM_DMP_COMP_NUM_MWRAP) | 1077 | nmw = (val & BWFM_DMP_COMP_NUM_MWRAP) | |
1078 | >> BWFM_DMP_COMP_NUM_MWRAP_S; | 1078 | >> BWFM_DMP_COMP_NUM_MWRAP_S; | |
1079 | nsw = (val & BWFM_DMP_COMP_NUM_SWRAP) | 1079 | nsw = (val & BWFM_DMP_COMP_NUM_SWRAP) | |
1080 | >> BWFM_DMP_COMP_NUM_SWRAP_S; | 1080 | >> BWFM_DMP_COMP_NUM_SWRAP_S; | |
1081 | rev = (val & BWFM_DMP_COMP_REVISION) | 1081 | rev = (val & BWFM_DMP_COMP_REVISION) | |
1082 | >> BWFM_DMP_COMP_REVISION_S; | 1082 | >> BWFM_DMP_COMP_REVISION_S; | |
1083 | 1083 | |||
1084 | if (nmw + nsw == 0 && id != BWFM_AGENT_CORE_PMU) | 1084 | if (nmw + nsw == 0 && id != BWFM_AGENT_CORE_PMU) | |
1085 | continue; | 1085 | continue; | |
1086 | 1086 | |||
1087 | if (bwfm_chip_dmp_get_regaddr(sc, &erom, &base, &wrap)) | 1087 | if (bwfm_chip_dmp_get_regaddr(sc, &erom, &base, &wrap)) | |
1088 | continue; | 1088 | continue; | |
1089 | 1089 | |||
1090 | core = kmem_alloc(sizeof(*core), KM_SLEEP); | 1090 | core = kmem_alloc(sizeof(*core), KM_SLEEP); | |
1091 | core->co_id = id; | 1091 | core->co_id = id; | |
1092 | core->co_base = base; | 1092 | core->co_base = base; | |
1093 | core->co_wrapbase = wrap; | 1093 | core->co_wrapbase = wrap; | |
1094 | core->co_rev = rev; | 1094 | core->co_rev = rev; | |
1095 | LIST_INSERT_HEAD(&sc->sc_chip.ch_list, core, co_link); | 1095 | LIST_INSERT_HEAD(&sc->sc_chip.ch_list, core, co_link); | |
1096 | } | 1096 | } | |
1097 | } | 1097 | } | |
1098 | 1098 | |||
1099 | int | 1099 | int | |
1100 | bwfm_chip_dmp_get_regaddr(struct bwfm_softc *sc, uint32_t *erom, | 1100 | bwfm_chip_dmp_get_regaddr(struct bwfm_softc *sc, uint32_t *erom, | |
1101 | uint32_t *base, uint32_t *wrap) | 1101 | uint32_t *base, uint32_t *wrap) | |
1102 | { | 1102 | { | |
1103 | uint8_t type = 0, mpnum __unused = 0; | 1103 | uint8_t type = 0, mpnum __unused = 0; | |
1104 | uint8_t stype, sztype, wraptype; | 1104 | uint8_t stype, sztype, wraptype; | |
1105 | uint32_t val; | 1105 | uint32_t val; | |
1106 | 1106 | |||
1107 | *base = 0; | 1107 | *base = 0; | |
1108 | *wrap = 0; | 1108 | *wrap = 0; | |
1109 | 1109 | |||
1110 | val = sc->sc_buscore_ops->bc_read(sc, *erom); | 1110 | val = sc->sc_buscore_ops->bc_read(sc, *erom); | |
1111 | type = val & BWFM_DMP_DESC_MASK; | 1111 | type = val & BWFM_DMP_DESC_MASK; | |
1112 | if (type == BWFM_DMP_DESC_MASTER_PORT) { | 1112 | if (type == BWFM_DMP_DESC_MASTER_PORT) { | |
1113 | mpnum = (val & BWFM_DMP_MASTER_PORT_NUM) | 1113 | mpnum = (val & BWFM_DMP_MASTER_PORT_NUM) | |
1114 | >> BWFM_DMP_MASTER_PORT_NUM_S; | 1114 | >> BWFM_DMP_MASTER_PORT_NUM_S; | |
1115 | wraptype = BWFM_DMP_SLAVE_TYPE_MWRAP; | 1115 | wraptype = BWFM_DMP_SLAVE_TYPE_MWRAP; | |
1116 | *erom += 4; | 1116 | *erom += 4; | |
1117 | } else if ((type & ~BWFM_DMP_DESC_ADDRSIZE_GT32) == | 1117 | } else if ((type & ~BWFM_DMP_DESC_ADDRSIZE_GT32) == | |
1118 | BWFM_DMP_DESC_ADDRESS) | 1118 | BWFM_DMP_DESC_ADDRESS) | |
1119 | wraptype = BWFM_DMP_SLAVE_TYPE_SWRAP; | 1119 | wraptype = BWFM_DMP_SLAVE_TYPE_SWRAP; | |
1120 | else | 1120 | else | |
1121 | return 1; | 1121 | return 1; | |
1122 | 1122 | |||
1123 | do { | 1123 | do { | |
1124 | do { | 1124 | do { | |
1125 | val = sc->sc_buscore_ops->bc_read(sc, *erom); | 1125 | val = sc->sc_buscore_ops->bc_read(sc, *erom); | |
1126 | type = val & BWFM_DMP_DESC_MASK; | 1126 | type = val & BWFM_DMP_DESC_MASK; | |
1127 | if (type == BWFM_DMP_DESC_COMPONENT) | 1127 | if (type == BWFM_DMP_DESC_COMPONENT) | |
1128 | return 0; | 1128 | return 0; | |
1129 | if (type == BWFM_DMP_DESC_EOT) | 1129 | if (type == BWFM_DMP_DESC_EOT) | |
1130 | return 1; | 1130 | return 1; | |
1131 | *erom += 4; | 1131 | *erom += 4; | |
1132 | } while ((type & ~BWFM_DMP_DESC_ADDRSIZE_GT32) != | 1132 | } while ((type & ~BWFM_DMP_DESC_ADDRSIZE_GT32) != | |
1133 | BWFM_DMP_DESC_ADDRESS); | 1133 | BWFM_DMP_DESC_ADDRESS); | |
1134 | 1134 | |||
1135 | if (type & BWFM_DMP_DESC_ADDRSIZE_GT32) | 1135 | if (type & BWFM_DMP_DESC_ADDRSIZE_GT32) | |
1136 | *erom += 4; | 1136 | *erom += 4; | |
1137 | 1137 | |||
1138 | sztype = (val & BWFM_DMP_SLAVE_SIZE_TYPE) | 1138 | sztype = (val & BWFM_DMP_SLAVE_SIZE_TYPE) | |
1139 | >> BWFM_DMP_SLAVE_SIZE_TYPE_S; | 1139 | >> BWFM_DMP_SLAVE_SIZE_TYPE_S; | |
1140 | if (sztype == BWFM_DMP_SLAVE_SIZE_DESC) { | 1140 | if (sztype == BWFM_DMP_SLAVE_SIZE_DESC) { | |
1141 | val = sc->sc_buscore_ops->bc_read(sc, *erom); | 1141 | val = sc->sc_buscore_ops->bc_read(sc, *erom); | |
1142 | type = val & BWFM_DMP_DESC_MASK; | 1142 | type = val & BWFM_DMP_DESC_MASK; | |
1143 | if (type & BWFM_DMP_DESC_ADDRSIZE_GT32) | 1143 | if (type & BWFM_DMP_DESC_ADDRSIZE_GT32) | |
1144 | *erom += 8; | 1144 | *erom += 8; | |
1145 | else | 1145 | else | |
1146 | *erom += 4; | 1146 | *erom += 4; | |
1147 | } | 1147 | } | |
1148 | if (sztype != BWFM_DMP_SLAVE_SIZE_4K) | 1148 | if (sztype != BWFM_DMP_SLAVE_SIZE_4K) | |
1149 | continue; | 1149 | continue; | |
1150 | 1150 | |||
1151 | stype = (val & BWFM_DMP_SLAVE_TYPE) >> BWFM_DMP_SLAVE_TYPE_S; | 1151 | stype = (val & BWFM_DMP_SLAVE_TYPE) >> BWFM_DMP_SLAVE_TYPE_S; | |
1152 | if (*base == 0 && stype == BWFM_DMP_SLAVE_TYPE_SLAVE) | 1152 | if (*base == 0 && stype == BWFM_DMP_SLAVE_TYPE_SLAVE) | |
1153 | *base = val & BWFM_DMP_SLAVE_ADDR_BASE; | 1153 | *base = val & BWFM_DMP_SLAVE_ADDR_BASE; | |
1154 | if (*wrap == 0 && stype == wraptype) | 1154 | if (*wrap == 0 && stype == wraptype) | |
1155 | *wrap = val & BWFM_DMP_SLAVE_ADDR_BASE; | 1155 | *wrap = val & BWFM_DMP_SLAVE_ADDR_BASE; | |
1156 | } while (*base == 0 || *wrap == 0); | 1156 | } while (*base == 0 || *wrap == 0); | |
1157 | 1157 | |||
1158 | return 0; | 1158 | return 0; | |
1159 | } | 1159 | } | |
1160 | 1160 | |||
1161 | /* Core configuration */ | 1161 | /* Core configuration */ | |
1162 | int | 1162 | int | |
1163 | bwfm_chip_set_active(struct bwfm_softc *sc, const uint32_t rstvec) | 1163 | bwfm_chip_set_active(struct bwfm_softc *sc, const uint32_t rstvec) | |
1164 | { | 1164 | { | |
1165 | if (bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CR4) != NULL) | 1165 | if (bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CR4) != NULL) | |
1166 | return bwfm_chip_cr4_set_active(sc, rstvec); | 1166 | return bwfm_chip_cr4_set_active(sc, rstvec); | |
1167 | if (bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CA7) != NULL) | 1167 | if (bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CA7) != NULL) | |
1168 | return bwfm_chip_ca7_set_active(sc, rstvec); | 1168 | return bwfm_chip_ca7_set_active(sc, rstvec); | |
1169 | if (bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CM3) != NULL) | 1169 | if (bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CM3) != NULL) | |
1170 | return bwfm_chip_cm3_set_active(sc); | 1170 | return bwfm_chip_cm3_set_active(sc); | |
1171 | return 1; | 1171 | return 1; | |
1172 | } | 1172 | } | |
1173 | 1173 | |||
1174 | void | 1174 | void | |
1175 | bwfm_chip_set_passive(struct bwfm_softc *sc) | 1175 | bwfm_chip_set_passive(struct bwfm_softc *sc) | |
1176 | { | 1176 | { | |
1177 | if (bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CR4) != NULL) { | 1177 | if (bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CR4) != NULL) { | |
1178 | bwfm_chip_cr4_set_passive(sc); | 1178 | bwfm_chip_cr4_set_passive(sc); | |
1179 | return; | 1179 | return; | |
1180 | } | 1180 | } | |
1181 | if (bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CA7) != NULL) { | 1181 | if (bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CA7) != NULL) { | |
1182 | bwfm_chip_ca7_set_passive(sc); | 1182 | bwfm_chip_ca7_set_passive(sc); | |
1183 | return; | 1183 | return; | |
1184 | } | 1184 | } | |
1185 | if (bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CM3) != NULL) { | 1185 | if (bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CM3) != NULL) { | |
1186 | bwfm_chip_cm3_set_passive(sc); | 1186 | bwfm_chip_cm3_set_passive(sc); | |
1187 | return; | 1187 | return; | |
1188 | } | 1188 | } | |
1189 | } | 1189 | } | |
1190 | 1190 | |||
1191 | int | 1191 | int | |
1192 | bwfm_chip_cr4_set_active(struct bwfm_softc *sc, const uint32_t rstvec) | 1192 | bwfm_chip_cr4_set_active(struct bwfm_softc *sc, const uint32_t rstvec) | |
1193 | { | 1193 | { | |
1194 | struct bwfm_core *core; | 1194 | struct bwfm_core *core; | |
1195 | 1195 | |||
1196 | sc->sc_buscore_ops->bc_activate(sc, rstvec); | 1196 | sc->sc_buscore_ops->bc_activate(sc, rstvec); | |
1197 | core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CR4); | 1197 | core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CR4); | |
1198 | sc->sc_chip.ch_core_reset(sc, core, | 1198 | sc->sc_chip.ch_core_reset(sc, core, | |
1199 | BWFM_AGENT_IOCTL_ARMCR4_CPUHALT, 0, 0); | 1199 | BWFM_AGENT_IOCTL_ARMCR4_CPUHALT, 0, 0); | |
1200 | 1200 | |||
1201 | return 0; | 1201 | return 0; | |
1202 | } | 1202 | } | |
1203 | 1203 | |||
1204 | void | 1204 | void | |
1205 | bwfm_chip_cr4_set_passive(struct bwfm_softc *sc) | 1205 | bwfm_chip_cr4_set_passive(struct bwfm_softc *sc) | |
1206 | { | 1206 | { | |
1207 | struct bwfm_core *core; | 1207 | struct bwfm_core *core; | |
1208 | uint32_t val; | 1208 | uint32_t val; | |
1209 | 1209 | |||
1210 | core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CR4); | 1210 | core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CR4); | |
1211 | val = sc->sc_buscore_ops->bc_read(sc, | 1211 | val = sc->sc_buscore_ops->bc_read(sc, | |
1212 | core->co_wrapbase + BWFM_AGENT_IOCTL); | 1212 | core->co_wrapbase + BWFM_AGENT_IOCTL); | |
1213 | sc->sc_chip.ch_core_reset(sc, core, | 1213 | sc->sc_chip.ch_core_reset(sc, core, | |
1214 | val & BWFM_AGENT_IOCTL_ARMCR4_CPUHALT, | 1214 | val & BWFM_AGENT_IOCTL_ARMCR4_CPUHALT, | |
1215 | BWFM_AGENT_IOCTL_ARMCR4_CPUHALT, | 1215 | BWFM_AGENT_IOCTL_ARMCR4_CPUHALT, | |
1216 | BWFM_AGENT_IOCTL_ARMCR4_CPUHALT); | 1216 | BWFM_AGENT_IOCTL_ARMCR4_CPUHALT); | |
1217 | 1217 | |||
1218 | core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_80211); | 1218 | core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_80211); | |
1219 | sc->sc_chip.ch_core_reset(sc, core, BWFM_AGENT_D11_IOCTL_PHYRESET | | 1219 | sc->sc_chip.ch_core_reset(sc, core, BWFM_AGENT_D11_IOCTL_PHYRESET | | |
1220 | BWFM_AGENT_D11_IOCTL_PHYCLOCKEN, BWFM_AGENT_D11_IOCTL_PHYCLOCKEN, | 1220 | BWFM_AGENT_D11_IOCTL_PHYCLOCKEN, BWFM_AGENT_D11_IOCTL_PHYCLOCKEN, | |
1221 | BWFM_AGENT_D11_IOCTL_PHYCLOCKEN); | 1221 | BWFM_AGENT_D11_IOCTL_PHYCLOCKEN); | |
1222 | } | 1222 | } | |
1223 | 1223 | |||
1224 | int | 1224 | int | |
1225 | bwfm_chip_ca7_set_active(struct bwfm_softc *sc, const uint32_t rstvec) | 1225 | bwfm_chip_ca7_set_active(struct bwfm_softc *sc, const uint32_t rstvec) | |
1226 | { | 1226 | { | |
1227 | struct bwfm_core *core; | 1227 | struct bwfm_core *core; | |
1228 | 1228 | |||
1229 | sc->sc_buscore_ops->bc_activate(sc, rstvec); | 1229 | sc->sc_buscore_ops->bc_activate(sc, rstvec); | |
1230 | core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CA7); | 1230 | core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CA7); | |
1231 | sc->sc_chip.ch_core_reset(sc, core, | 1231 | sc->sc_chip.ch_core_reset(sc, core, | |
1232 | BWFM_AGENT_IOCTL_ARMCR4_CPUHALT, 0, 0); | 1232 | BWFM_AGENT_IOCTL_ARMCR4_CPUHALT, 0, 0); | |
1233 | 1233 | |||
1234 | return 0; | 1234 | return 0; | |
1235 | } | 1235 | } | |
1236 | 1236 | |||
1237 | void | 1237 | void | |
1238 | bwfm_chip_ca7_set_passive(struct bwfm_softc *sc) | 1238 | bwfm_chip_ca7_set_passive(struct bwfm_softc *sc) | |
1239 | { | 1239 | { | |
1240 | struct bwfm_core *core; | 1240 | struct bwfm_core *core; | |
1241 | uint32_t val; | 1241 | uint32_t val; | |
1242 | 1242 | |||
1243 | core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CA7); | 1243 | core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CA7); | |
1244 | val = sc->sc_buscore_ops->bc_read(sc, | 1244 | val = sc->sc_buscore_ops->bc_read(sc, | |
1245 | core->co_wrapbase + BWFM_AGENT_IOCTL); | 1245 | core->co_wrapbase + BWFM_AGENT_IOCTL); | |
1246 | sc->sc_chip.ch_core_reset(sc, core, | 1246 | sc->sc_chip.ch_core_reset(sc, core, | |
1247 | val & BWFM_AGENT_IOCTL_ARMCR4_CPUHALT, | 1247 | val & BWFM_AGENT_IOCTL_ARMCR4_CPUHALT, | |
1248 | BWFM_AGENT_IOCTL_ARMCR4_CPUHALT, | 1248 | BWFM_AGENT_IOCTL_ARMCR4_CPUHALT, | |
1249 | BWFM_AGENT_IOCTL_ARMCR4_CPUHALT); | 1249 | BWFM_AGENT_IOCTL_ARMCR4_CPUHALT); | |
1250 | 1250 | |||
1251 | core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_80211); | 1251 | core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_80211); | |
1252 | sc->sc_chip.ch_core_reset(sc, core, BWFM_AGENT_D11_IOCTL_PHYRESET | | 1252 | sc->sc_chip.ch_core_reset(sc, core, BWFM_AGENT_D11_IOCTL_PHYRESET | | |
1253 | BWFM_AGENT_D11_IOCTL_PHYCLOCKEN, BWFM_AGENT_D11_IOCTL_PHYCLOCKEN, | 1253 | BWFM_AGENT_D11_IOCTL_PHYCLOCKEN, BWFM_AGENT_D11_IOCTL_PHYCLOCKEN, | |
1254 | BWFM_AGENT_D11_IOCTL_PHYCLOCKEN); | 1254 | BWFM_AGENT_D11_IOCTL_PHYCLOCKEN); | |
1255 | } | 1255 | } | |
1256 | 1256 | |||
1257 | int | 1257 | int | |
1258 | bwfm_chip_cm3_set_active(struct bwfm_softc *sc) | 1258 | bwfm_chip_cm3_set_active(struct bwfm_softc *sc) | |
1259 | { | 1259 | { | |
1260 | struct bwfm_core *core; | 1260 | struct bwfm_core *core; | |
1261 | 1261 | |||
1262 | core = bwfm_chip_get_core(sc, BWFM_AGENT_INTERNAL_MEM); | 1262 | core = bwfm_chip_get_core(sc, BWFM_AGENT_INTERNAL_MEM); | |
1263 | if (!sc->sc_chip.ch_core_isup(sc, core)) | 1263 | if (!sc->sc_chip.ch_core_isup(sc, core)) | |
1264 | return 1; | 1264 | return 1; | |
1265 | 1265 | |||
1266 | sc->sc_buscore_ops->bc_activate(sc, 0); | 1266 | sc->sc_buscore_ops->bc_activate(sc, 0); | |
1267 | 1267 | |||
1268 | core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CM3); | 1268 | core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CM3); | |
1269 | sc->sc_chip.ch_core_reset(sc, core, 0, 0, 0); | 1269 | sc->sc_chip.ch_core_reset(sc, core, 0, 0, 0); | |
1270 | 1270 | |||
1271 | return 0; | 1271 | return 0; | |
1272 | } | 1272 | } | |
1273 | 1273 | |||
1274 | void | 1274 | void | |
1275 | bwfm_chip_cm3_set_passive(struct bwfm_softc *sc) | 1275 | bwfm_chip_cm3_set_passive(struct bwfm_softc *sc) | |
1276 | { | 1276 | { | |
1277 | struct bwfm_core *core; | 1277 | struct bwfm_core *core; | |
1278 | 1278 | |||
1279 | core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CM3); | 1279 | core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CM3); | |
1280 | sc->sc_chip.ch_core_disable(sc, core, 0, 0); | 1280 | sc->sc_chip.ch_core_disable(sc, core, 0, 0); | |
1281 | core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_80211); | 1281 | core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_80211); | |
1282 | sc->sc_chip.ch_core_reset(sc, core, BWFM_AGENT_D11_IOCTL_PHYRESET | | 1282 | sc->sc_chip.ch_core_reset(sc, core, BWFM_AGENT_D11_IOCTL_PHYRESET | | |
1283 | BWFM_AGENT_D11_IOCTL_PHYCLOCKEN, BWFM_AGENT_D11_IOCTL_PHYCLOCKEN, | 1283 | BWFM_AGENT_D11_IOCTL_PHYCLOCKEN, BWFM_AGENT_D11_IOCTL_PHYCLOCKEN, | |
1284 | BWFM_AGENT_D11_IOCTL_PHYCLOCKEN); | 1284 | BWFM_AGENT_D11_IOCTL_PHYCLOCKEN); | |
1285 | core = bwfm_chip_get_core(sc, BWFM_AGENT_INTERNAL_MEM); | 1285 | core = bwfm_chip_get_core(sc, BWFM_AGENT_INTERNAL_MEM); | |
1286 | sc->sc_chip.ch_core_reset(sc, core, 0, 0, 0); | 1286 | sc->sc_chip.ch_core_reset(sc, core, 0, 0, 0); | |
1287 | 1287 | |||
1288 | if (sc->sc_chip.ch_chip == BRCM_CC_43430_CHIP_ID) { | 1288 | if (sc->sc_chip.ch_chip == BRCM_CC_43430_CHIP_ID) { | |
1289 | sc->sc_buscore_ops->bc_write(sc, | 1289 | sc->sc_buscore_ops->bc_write(sc, | |
1290 | core->co_base + BWFM_SOCRAM_BANKIDX, 3); | 1290 | core->co_base + BWFM_SOCRAM_BANKIDX, 3); | |
1291 | sc->sc_buscore_ops->bc_write(sc, | 1291 | sc->sc_buscore_ops->bc_write(sc, | |
1292 | core->co_base + BWFM_SOCRAM_BANKPDA, 0); | 1292 | core->co_base + BWFM_SOCRAM_BANKPDA, 0); | |
1293 | } | 1293 | } | |
1294 | } | 1294 | } | |
1295 | 1295 | |||
1296 | int | 1296 | int | |
1297 | bwfm_chip_sr_capable(struct bwfm_softc *sc) | 1297 | bwfm_chip_sr_capable(struct bwfm_softc *sc) | |
1298 | { | 1298 | { | |
1299 | struct bwfm_core *core; | 1299 | struct bwfm_core *core; | |
1300 | uint32_t reg; | 1300 | uint32_t reg; | |
1301 | 1301 | |||
1302 | if (sc->sc_chip.ch_pmurev < 17) | 1302 | if (sc->sc_chip.ch_pmurev < 17) | |
1303 | return 0; | 1303 | return 0; | |
1304 | 1304 | |||
1305 | switch (sc->sc_chip.ch_chip) { | 1305 | switch (sc->sc_chip.ch_chip) { | |
1306 | case BRCM_CC_4345_CHIP_ID: | 1306 | case BRCM_CC_4345_CHIP_ID: | |
1307 | case BRCM_CC_4354_CHIP_ID: | 1307 | case BRCM_CC_4354_CHIP_ID: | |
1308 | case BRCM_CC_4356_CHIP_ID: | 1308 | case BRCM_CC_4356_CHIP_ID: | |
1309 | core = bwfm_chip_get_pmu(sc); | 1309 | core = bwfm_chip_get_pmu(sc); | |
1310 | sc->sc_buscore_ops->bc_write(sc, core->co_base + | 1310 | sc->sc_buscore_ops->bc_write(sc, core->co_base + | |
1311 | BWFM_CHIP_REG_CHIPCONTROL_ADDR, 3); | 1311 | BWFM_CHIP_REG_CHIPCONTROL_ADDR, 3); | |
1312 | reg = sc->sc_buscore_ops->bc_read(sc, core->co_base + | 1312 | reg = sc->sc_buscore_ops->bc_read(sc, core->co_base + | |
1313 | BWFM_CHIP_REG_CHIPCONTROL_DATA); | 1313 | BWFM_CHIP_REG_CHIPCONTROL_DATA); | |
1314 | return (reg & (1 << 2)) != 0; | 1314 | return (reg & (1 << 2)) != 0; | |
1315 | case BRCM_CC_43241_CHIP_ID: | 1315 | case BRCM_CC_43241_CHIP_ID: | |
1316 | case BRCM_CC_4335_CHIP_ID: | 1316 | case BRCM_CC_4335_CHIP_ID: | |
1317 | case BRCM_CC_4339_CHIP_ID: | 1317 | case BRCM_CC_4339_CHIP_ID: | |
1318 | core = bwfm_chip_get_pmu(sc); | 1318 | core = bwfm_chip_get_pmu(sc); | |
1319 | sc->sc_buscore_ops->bc_write(sc, core->co_base + | 1319 | sc->sc_buscore_ops->bc_write(sc, core->co_base + | |
1320 | BWFM_CHIP_REG_CHIPCONTROL_ADDR, 3); | 1320 | BWFM_CHIP_REG_CHIPCONTROL_ADDR, 3); | |
1321 | reg = sc->sc_buscore_ops->bc_read(sc, core->co_base + | 1321 | reg = sc->sc_buscore_ops->bc_read(sc, core->co_base + | |
1322 | BWFM_CHIP_REG_CHIPCONTROL_DATA); | 1322 | BWFM_CHIP_REG_CHIPCONTROL_DATA); | |
1323 | return reg != 0; | 1323 | return reg != 0; | |
1324 | case BRCM_CC_43430_CHIP_ID: | 1324 | case BRCM_CC_43430_CHIP_ID: | |
1325 | core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_CHIPCOMMON); | 1325 | core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_CHIPCOMMON); | |
1326 | reg = sc->sc_buscore_ops->bc_read(sc, core->co_base + | 1326 | reg = sc->sc_buscore_ops->bc_read(sc, core->co_base + | |
1327 | BWFM_CHIP_REG_SR_CONTROL1); | 1327 | BWFM_CHIP_REG_SR_CONTROL1); | |
1328 | return reg != 0; | 1328 | return reg != 0; | |
1329 | default: | 1329 | default: | |
1330 | core = bwfm_chip_get_pmu(sc); | 1330 | core = bwfm_chip_get_pmu(sc); | |
1331 | reg = sc->sc_buscore_ops->bc_read(sc, core->co_base + | 1331 | reg = sc->sc_buscore_ops->bc_read(sc, core->co_base + | |
1332 | BWFM_CHIP_REG_PMUCAPABILITIES_EXT); | 1332 | BWFM_CHIP_REG_PMUCAPABILITIES_EXT); | |
1333 | if ((reg & BWFM_CHIP_REG_PMUCAPABILITIES_SR_SUPP) == 0) | 1333 | if ((reg & BWFM_CHIP_REG_PMUCAPABILITIES_SR_SUPP) == 0) | |
1334 | return 0; | 1334 | return 0; | |
1335 | reg = sc->sc_buscore_ops->bc_read(sc, core->co_base + | 1335 | reg = sc->sc_buscore_ops->bc_read(sc, core->co_base + | |
1336 | BWFM_CHIP_REG_RETENTION_CTL); | 1336 | BWFM_CHIP_REG_RETENTION_CTL); | |
1337 | return (reg & (BWFM_CHIP_REG_RETENTION_CTL_MACPHY_DIS | | 1337 | return (reg & (BWFM_CHIP_REG_RETENTION_CTL_MACPHY_DIS | | |
1338 | BWFM_CHIP_REG_RETENTION_CTL_LOGIC_DIS)) == 0; | 1338 | BWFM_CHIP_REG_RETENTION_CTL_LOGIC_DIS)) == 0; | |
1339 | } | 1339 | } | |
1340 | } | 1340 | } | |
1341 | 1341 | |||
1342 | /* RAM size helpers */ | 1342 | /* RAM size helpers */ | |
1343 | void | 1343 | void | |
1344 | bwfm_chip_socram_ramsize(struct bwfm_softc *sc, struct bwfm_core *core) | 1344 | bwfm_chip_socram_ramsize(struct bwfm_softc *sc, struct bwfm_core *core) | |
1345 | { | 1345 | { | |
1346 | uint32_t coreinfo, nb, lss, banksize, bankinfo; | 1346 | uint32_t coreinfo, nb, lss, banksize, bankinfo; | |
1347 | uint32_t ramsize = 0, srsize = 0; | 1347 | uint32_t ramsize = 0, srsize = 0; | |
1348 | int i; | 1348 | int i; | |
1349 | 1349 | |||
1350 | if (!sc->sc_chip.ch_core_isup(sc, core)) | 1350 | if (!sc->sc_chip.ch_core_isup(sc, core)) | |
1351 | sc->sc_chip.ch_core_reset(sc, core, 0, 0, 0); | 1351 | sc->sc_chip.ch_core_reset(sc, core, 0, 0, 0); | |
1352 | 1352 | |||
1353 | coreinfo = sc->sc_buscore_ops->bc_read(sc, | 1353 | coreinfo = sc->sc_buscore_ops->bc_read(sc, | |
1354 | core->co_base + BWFM_SOCRAM_COREINFO); | 1354 | core->co_base + BWFM_SOCRAM_COREINFO); | |
1355 | nb = (coreinfo & BWFM_SOCRAM_COREINFO_SRNB_MASK) | 1355 | nb = (coreinfo & BWFM_SOCRAM_COREINFO_SRNB_MASK) | |
1356 | >> BWFM_SOCRAM_COREINFO_SRNB_SHIFT; | 1356 | >> BWFM_SOCRAM_COREINFO_SRNB_SHIFT; | |
1357 | 1357 | |||
1358 | if (core->co_rev <= 7 || core->co_rev == 12) { | 1358 | if (core->co_rev <= 7 || core->co_rev == 12) { | |
1359 | banksize = coreinfo & BWFM_SOCRAM_COREINFO_SRBSZ_MASK; | 1359 | banksize = coreinfo & BWFM_SOCRAM_COREINFO_SRBSZ_MASK; | |
1360 | lss = (coreinfo & BWFM_SOCRAM_COREINFO_LSS_MASK) | 1360 | lss = (coreinfo & BWFM_SOCRAM_COREINFO_LSS_MASK) | |
1361 | >> BWFM_SOCRAM_COREINFO_LSS_SHIFT; | 1361 | >> BWFM_SOCRAM_COREINFO_LSS_SHIFT; | |
1362 | if (lss != 0) | 1362 | if (lss != 0) | |
1363 | nb--; | 1363 | nb--; | |
1364 | ramsize = nb * (1 << (banksize + BWFM_SOCRAM_COREINFO_SRBSZ_BASE)); | 1364 | ramsize = nb * (1 << (banksize + BWFM_SOCRAM_COREINFO_SRBSZ_BASE)); | |
1365 | if (lss != 0) | 1365 | if (lss != 0) | |
1366 | ramsize += (1 << ((lss - 1) + BWFM_SOCRAM_COREINFO_SRBSZ_BASE)); | 1366 | ramsize += (1 << ((lss - 1) + BWFM_SOCRAM_COREINFO_SRBSZ_BASE)); | |
1367 | } else { | 1367 | } else { | |
1368 | for (i = 0; i < nb; i++) { | 1368 | for (i = 0; i < nb; i++) { | |
1369 | sc->sc_buscore_ops->bc_write(sc, | 1369 | sc->sc_buscore_ops->bc_write(sc, | |
1370 | core->co_base + BWFM_SOCRAM_BANKIDX, | 1370 | core->co_base + BWFM_SOCRAM_BANKIDX, | |
1371 | (BWFM_SOCRAM_BANKIDX_MEMTYPE_RAM << | 1371 | (BWFM_SOCRAM_BANKIDX_MEMTYPE_RAM << | |
1372 | BWFM_SOCRAM_BANKIDX_MEMTYPE_SHIFT) | i); | 1372 | BWFM_SOCRAM_BANKIDX_MEMTYPE_SHIFT) | i); | |
1373 | bankinfo = sc->sc_buscore_ops->bc_read(sc, | 1373 | bankinfo = sc->sc_buscore_ops->bc_read(sc, | |
1374 | core->co_base + BWFM_SOCRAM_BANKINFO); | 1374 | core->co_base + BWFM_SOCRAM_BANKINFO); | |
1375 | banksize = ((bankinfo & BWFM_SOCRAM_BANKINFO_SZMASK) + 1) | 1375 | banksize = ((bankinfo & BWFM_SOCRAM_BANKINFO_SZMASK) + 1) | |
1376 | * BWFM_SOCRAM_BANKINFO_SZBASE; | 1376 | * BWFM_SOCRAM_BANKINFO_SZBASE; | |
1377 | ramsize += banksize; | 1377 | ramsize += banksize; | |
1378 | if (bankinfo & BWFM_SOCRAM_BANKINFO_RETNTRAM_MASK) | 1378 | if (bankinfo & BWFM_SOCRAM_BANKINFO_RETNTRAM_MASK) | |
1379 | srsize += banksize; | 1379 | srsize += banksize; | |
1380 | } | 1380 | } | |
1381 | } | 1381 | } | |
1382 | 1382 | |||
1383 | switch (sc->sc_chip.ch_chip) { | 1383 | switch (sc->sc_chip.ch_chip) { | |
1384 | case BRCM_CC_4334_CHIP_ID: | 1384 | case BRCM_CC_4334_CHIP_ID: | |
1385 | if (sc->sc_chip.ch_chiprev < 2) | 1385 | if (sc->sc_chip.ch_chiprev < 2) | |
1386 | srsize = 32 * 1024; | 1386 | srsize = 32 * 1024; | |
1387 | break; | 1387 | break; | |
1388 | case BRCM_CC_43430_CHIP_ID: | 1388 | case BRCM_CC_43430_CHIP_ID: | |
1389 | srsize = 64 * 1024; | 1389 | srsize = 64 * 1024; | |
1390 | break; | 1390 | break; | |
1391 | default: | 1391 | default: | |
1392 | break; | 1392 | break; | |
1393 | } | 1393 | } | |
1394 | 1394 | |||
1395 | sc->sc_chip.ch_ramsize = ramsize; | 1395 | sc->sc_chip.ch_ramsize = ramsize; | |
1396 | sc->sc_chip.ch_srsize = srsize; | 1396 | sc->sc_chip.ch_srsize = srsize; | |
1397 | } | 1397 | } | |
1398 | 1398 | |||
1399 | void | 1399 | void | |
1400 | bwfm_chip_sysmem_ramsize(struct bwfm_softc *sc, struct bwfm_core *core) | 1400 | bwfm_chip_sysmem_ramsize(struct bwfm_softc *sc, struct bwfm_core *core) | |
1401 | { | 1401 | { | |
1402 | uint32_t coreinfo, nb, banksize, bankinfo; | 1402 | uint32_t coreinfo, nb, banksize, bankinfo; | |
1403 | uint32_t ramsize = 0; | 1403 | uint32_t ramsize = 0; | |
1404 | int i; | 1404 | int i; | |
1405 | 1405 | |||
1406 | if (!sc->sc_chip.ch_core_isup(sc, core)) | 1406 | if (!sc->sc_chip.ch_core_isup(sc, core)) | |
1407 | sc->sc_chip.ch_core_reset(sc, core, 0, 0, 0); | 1407 | sc->sc_chip.ch_core_reset(sc, core, 0, 0, 0); | |
1408 | 1408 | |||
1409 | coreinfo = sc->sc_buscore_ops->bc_read(sc, | 1409 | coreinfo = sc->sc_buscore_ops->bc_read(sc, | |
1410 | core->co_base + BWFM_SOCRAM_COREINFO); | 1410 | core->co_base + BWFM_SOCRAM_COREINFO); | |
1411 | nb = (coreinfo & BWFM_SOCRAM_COREINFO_SRNB_MASK) | 1411 | nb = (coreinfo & BWFM_SOCRAM_COREINFO_SRNB_MASK) | |
1412 | >> BWFM_SOCRAM_COREINFO_SRNB_SHIFT; | 1412 | >> BWFM_SOCRAM_COREINFO_SRNB_SHIFT; | |
1413 | 1413 | |||
1414 | for (i = 0; i < nb; i++) { | 1414 | for (i = 0; i < nb; i++) { | |
1415 | sc->sc_buscore_ops->bc_write(sc, | 1415 | sc->sc_buscore_ops->bc_write(sc, | |
1416 | core->co_base + BWFM_SOCRAM_BANKIDX, | 1416 | core->co_base + BWFM_SOCRAM_BANKIDX, | |
1417 | (BWFM_SOCRAM_BANKIDX_MEMTYPE_RAM << | 1417 | (BWFM_SOCRAM_BANKIDX_MEMTYPE_RAM << | |
1418 | BWFM_SOCRAM_BANKIDX_MEMTYPE_SHIFT) | i); | 1418 | BWFM_SOCRAM_BANKIDX_MEMTYPE_SHIFT) | i); | |
1419 | bankinfo = sc->sc_buscore_ops->bc_read(sc, | 1419 | bankinfo = sc->sc_buscore_ops->bc_read(sc, | |
1420 | core->co_base + BWFM_SOCRAM_BANKINFO); | 1420 | core->co_base + BWFM_SOCRAM_BANKINFO); | |
1421 | banksize = ((bankinfo & BWFM_SOCRAM_BANKINFO_SZMASK) + 1) | 1421 | banksize = ((bankinfo & BWFM_SOCRAM_BANKINFO_SZMASK) + 1) | |
1422 | * BWFM_SOCRAM_BANKINFO_SZBASE; | 1422 | * BWFM_SOCRAM_BANKINFO_SZBASE; | |
1423 | ramsize += banksize; | 1423 | ramsize += banksize; | |
1424 | } | 1424 | } | |
1425 | 1425 | |||
1426 | sc->sc_chip.ch_ramsize = ramsize; | 1426 | sc->sc_chip.ch_ramsize = ramsize; | |
1427 | } | 1427 | } | |
1428 | 1428 | |||
1429 | void | 1429 | void | |
1430 | bwfm_chip_tcm_ramsize(struct bwfm_softc *sc, struct bwfm_core *core) | 1430 | bwfm_chip_tcm_ramsize(struct bwfm_softc *sc, struct bwfm_core *core) | |
1431 | { | 1431 | { | |
1432 | uint32_t cap, nab, nbb, totb, bxinfo, ramsize = 0; | 1432 | uint32_t cap, nab, nbb, totb, bxinfo, ramsize = 0; | |
1433 | int i; | 1433 | int i; | |
1434 | 1434 | |||
1435 | cap = sc->sc_buscore_ops->bc_read(sc, core->co_base + BWFM_ARMCR4_CAP); | 1435 | cap = sc->sc_buscore_ops->bc_read(sc, core->co_base + BWFM_ARMCR4_CAP); | |
1436 | nab = (cap & BWFM_ARMCR4_CAP_TCBANB_MASK) >> BWFM_ARMCR4_CAP_TCBANB_SHIFT; | 1436 | nab = (cap & BWFM_ARMCR4_CAP_TCBANB_MASK) >> BWFM_ARMCR4_CAP_TCBANB_SHIFT; | |
1437 | nbb = (cap & BWFM_ARMCR4_CAP_TCBBNB_MASK) >> BWFM_ARMCR4_CAP_TCBBNB_SHIFT; | 1437 | nbb = (cap & BWFM_ARMCR4_CAP_TCBBNB_MASK) >> BWFM_ARMCR4_CAP_TCBBNB_SHIFT; | |
1438 | totb = nab + nbb; | 1438 | totb = nab + nbb; | |
1439 | 1439 | |||
1440 | for (i = 0; i < totb; i++) { | 1440 | for (i = 0; i < totb; i++) { | |
1441 | sc->sc_buscore_ops->bc_write(sc, | 1441 | sc->sc_buscore_ops->bc_write(sc, | |
1442 | core->co_base + BWFM_ARMCR4_BANKIDX, i); | 1442 | core->co_base + BWFM_ARMCR4_BANKIDX, i); | |
1443 | bxinfo = sc->sc_buscore_ops->bc_read(sc, | 1443 | bxinfo = sc->sc_buscore_ops->bc_read(sc, | |
1444 | core->co_base + BWFM_ARMCR4_BANKINFO); | 1444 | core->co_base + BWFM_ARMCR4_BANKINFO); | |
1445 | ramsize += ((bxinfo & BWFM_ARMCR4_BANKINFO_BSZ_MASK) + 1) * | 1445 | ramsize += ((bxinfo & BWFM_ARMCR4_BANKINFO_BSZ_MASK) + 1) * | |
1446 | BWFM_ARMCR4_BANKINFO_BSZ_MULT; | 1446 | BWFM_ARMCR4_BANKINFO_BSZ_MULT; | |
1447 | } | 1447 | } | |
1448 | 1448 | |||
1449 | sc->sc_chip.ch_ramsize = ramsize; | 1449 | sc->sc_chip.ch_ramsize = ramsize; | |
1450 | } | 1450 | } | |
1451 | 1451 | |||
1452 | void | 1452 | void | |
1453 | bwfm_chip_tcm_rambase(struct bwfm_softc *sc) | 1453 | bwfm_chip_tcm_rambase(struct bwfm_softc *sc) | |
1454 | { | 1454 | { | |
1455 | switch (sc->sc_chip.ch_chip) { | 1455 | switch (sc->sc_chip.ch_chip) { | |
1456 | case BRCM_CC_4345_CHIP_ID: | 1456 | case BRCM_CC_4345_CHIP_ID: | |
1457 | sc->sc_chip.ch_rambase = 0x198000; | 1457 | sc->sc_chip.ch_rambase = 0x198000; | |
1458 | break; | 1458 | break; | |
1459 | case BRCM_CC_4335_CHIP_ID: | 1459 | case BRCM_CC_4335_CHIP_ID: | |
1460 | case BRCM_CC_4339_CHIP_ID: | 1460 | case BRCM_CC_4339_CHIP_ID: | |
1461 | case BRCM_CC_4350_CHIP_ID: | 1461 | case BRCM_CC_4350_CHIP_ID: | |
1462 | case BRCM_CC_4354_CHIP_ID: | 1462 | case BRCM_CC_4354_CHIP_ID: | |
1463 | case BRCM_CC_4356_CHIP_ID: | 1463 | case BRCM_CC_4356_CHIP_ID: | |
1464 | case BRCM_CC_43567_CHIP_ID: | 1464 | case BRCM_CC_43567_CHIP_ID: | |
1465 | case BRCM_CC_43569_CHIP_ID: | 1465 | case BRCM_CC_43569_CHIP_ID: | |
1466 | case BRCM_CC_43570_CHIP_ID: | 1466 | case BRCM_CC_43570_CHIP_ID: | |
1467 | case BRCM_CC_4358_CHIP_ID: | 1467 | case BRCM_CC_4358_CHIP_ID: | |
1468 | case BRCM_CC_4359_CHIP_ID: | 1468 | case BRCM_CC_4359_CHIP_ID: | |
1469 | case BRCM_CC_43602_CHIP_ID: | 1469 | case BRCM_CC_43602_CHIP_ID: | |
1470 | case BRCM_CC_4371_CHIP_ID: | 1470 | case BRCM_CC_4371_CHIP_ID: | |
1471 | sc->sc_chip.ch_rambase = 0x180000; | 1471 | sc->sc_chip.ch_rambase = 0x180000; | |
1472 | break; | 1472 | break; | |
1473 | case BRCM_CC_43465_CHIP_ID: | 1473 | case BRCM_CC_43465_CHIP_ID: | |
1474 | case BRCM_CC_43525_CHIP_ID: | 1474 | case BRCM_CC_43525_CHIP_ID: | |
1475 | case BRCM_CC_4365_CHIP_ID: | 1475 | case BRCM_CC_4365_CHIP_ID: | |
1476 | case BRCM_CC_4366_CHIP_ID: | 1476 | case BRCM_CC_4366_CHIP_ID: | |
1477 | sc->sc_chip.ch_rambase = 0x200000; | 1477 | sc->sc_chip.ch_rambase = 0x200000; | |
1478 | break; | 1478 | break; | |
1479 | case CY_CC_4373_CHIP_ID: | 1479 | case CY_CC_4373_CHIP_ID: | |
1480 | sc->sc_chip.ch_rambase = 0x160000; | 1480 | sc->sc_chip.ch_rambase = 0x160000; | |
1481 | break; | 1481 | break; | |
1482 | default: | 1482 | default: | |
1483 | printf("%s: unknown chip: %d\n", DEVNAME(sc), | 1483 | printf("%s: unknown chip: %d\n", DEVNAME(sc), | |
1484 | sc->sc_chip.ch_chip); | 1484 | sc->sc_chip.ch_chip); | |
1485 | break; | 1485 | break; | |
1486 | } | 1486 | } | |
1487 | } | 1487 | } | |
1488 | 1488 | |||
1489 | /* BCDC protocol implementation */ | 1489 | /* BCDC protocol implementation */ | |
1490 | int | 1490 | int | |
1491 | bwfm_proto_bcdc_query_dcmd(struct bwfm_softc *sc, int ifidx, | 1491 | bwfm_proto_bcdc_query_dcmd(struct bwfm_softc *sc, int ifidx, | |
1492 | int cmd, char *buf, size_t *len) | 1492 | int cmd, char *buf, size_t *len) | |
1493 | { | 1493 | { | |
1494 | struct bwfm_proto_bcdc_dcmd *dcmd; | 1494 | struct bwfm_proto_bcdc_dcmd *dcmd; | |
1495 | size_t size = sizeof(dcmd->hdr) + *len; | 1495 | size_t size = sizeof(dcmd->hdr) + *len; | |
1496 | int reqid; | 1496 | int reqid; | |
1497 | int ret = 1; | 1497 | int ret = 1; | |
1498 | 1498 | |||
1499 | reqid = sc->sc_bcdc_reqid++; | 1499 | reqid = sc->sc_bcdc_reqid++; | |
1500 | 1500 | |||
1501 | dcmd = kmem_zalloc(sizeof(*dcmd), KM_SLEEP); | 1501 | dcmd = kmem_zalloc(sizeof(*dcmd), KM_SLEEP); | |
1502 | if (*len > sizeof(dcmd->buf)) | 1502 | if (*len > sizeof(dcmd->buf)) | |
1503 | goto err; | 1503 | goto err; | |
1504 | 1504 | |||
1505 | dcmd->hdr.cmd = htole32(cmd); | 1505 | dcmd->hdr.cmd = htole32(cmd); | |
1506 | dcmd->hdr.len = htole32(*len); | 1506 | dcmd->hdr.len = htole32(*len); | |
1507 | dcmd->hdr.flags |= BWFM_BCDC_DCMD_GET; | 1507 | dcmd->hdr.flags |= BWFM_BCDC_DCMD_GET; | |
1508 | dcmd->hdr.flags |= BWFM_BCDC_DCMD_ID_SET(reqid); | 1508 | dcmd->hdr.flags |= BWFM_BCDC_DCMD_ID_SET(reqid); | |
1509 | dcmd->hdr.flags |= BWFM_BCDC_DCMD_IF_SET(ifidx); | 1509 | dcmd->hdr.flags |= BWFM_BCDC_DCMD_IF_SET(ifidx); | |
1510 | dcmd->hdr.flags = htole32(dcmd->hdr.flags); | 1510 | dcmd->hdr.flags = htole32(dcmd->hdr.flags); | |
1511 | memcpy(&dcmd->buf, buf, *len); | 1511 | memcpy(&dcmd->buf, buf, *len); | |
1512 | 1512 | |||
1513 | if (sc->sc_bus_ops->bs_txctl(sc, (void *)dcmd, | 1513 | if (sc->sc_bus_ops->bs_txctl(sc, (void *)dcmd, |
--- src/sys/dev/ic/bwi.c 2018/12/22 14:07:53 1.36
+++ src/sys/dev/ic/bwi.c 2020/01/29 14:14:55 1.37
@@ -1,1050 +1,1050 @@ | @@ -1,1050 +1,1050 @@ | |||
1 | /* $NetBSD: bwi.c,v 1.36 2018/12/22 14:07:53 maxv Exp $ */ | 1 | /* $NetBSD: bwi.c,v 1.37 2020/01/29 14:14:55 thorpej Exp $ */ | |
2 | /* $OpenBSD: bwi.c,v 1.74 2008/02/25 21:13:30 mglocker Exp $ */ | 2 | /* $OpenBSD: bwi.c,v 1.74 2008/02/25 21:13:30 mglocker Exp $ */ | |
3 | 3 | |||
4 | /* | 4 | /* | |
5 | * Copyright (c) 2007 The DragonFly Project. All rights reserved. | 5 | * Copyright (c) 2007 The DragonFly Project. All rights reserved. | |
6 | * | 6 | * | |
7 | * This code is derived from software contributed to The DragonFly Project | 7 | * This code is derived from software contributed to The DragonFly Project | |
8 | * by Sepherosa Ziehau <sepherosa@gmail.com> | 8 | * by Sepherosa Ziehau <sepherosa@gmail.com> | |
9 | * | 9 | * | |
10 | * Redistribution and use in source and binary forms, with or without | 10 | * Redistribution and use in source and binary forms, with or without | |
11 | * modification, are permitted provided that the following conditions | 11 | * modification, are permitted provided that the following conditions | |
12 | * are met: | 12 | * are met: | |
13 | * | 13 | * | |
14 | * 1. Redistributions of source code must retain the above copyright | 14 | * 1. Redistributions of source code must retain the above copyright | |
15 | * notice, this list of conditions and the following disclaimer. | 15 | * notice, this list of conditions and the following disclaimer. | |
16 | * 2. Redistributions in binary form must reproduce the above copyright | 16 | * 2. Redistributions in binary form must reproduce the above copyright | |
17 | * notice, this list of conditions and the following disclaimer in | 17 | * notice, this list of conditions and the following disclaimer in | |
18 | * the documentation and/or other materials provided with the | 18 | * the documentation and/or other materials provided with the | |
19 | * distribution. | 19 | * distribution. | |
20 | * 3. Neither the name of The DragonFly Project nor the names of its | 20 | * 3. Neither the name of The DragonFly Project nor the names of its | |
21 | * contributors may be used to endorse or promote products derived | 21 | * contributors may be used to endorse or promote products derived | |
22 | * from this software without specific, prior written permission. | 22 | * from this software without specific, prior written permission. | |
23 | * | 23 | * | |
24 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 24 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
25 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 25 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
26 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | 26 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
27 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | 27 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
28 | * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | 28 | * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
29 | * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, | 29 | * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
30 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | 30 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
31 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | 31 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | |
32 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | 32 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |
33 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | 33 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |
34 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 34 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
35 | * SUCH DAMAGE. | 35 | * SUCH DAMAGE. | |
36 | * | 36 | * | |
37 | * $DragonFly: src/sys/dev/netif/bwi/bwimac.c,v 1.1 2007/09/08 06:15:54 sephe Exp $ | 37 | * $DragonFly: src/sys/dev/netif/bwi/bwimac.c,v 1.1 2007/09/08 06:15:54 sephe Exp $ | |
38 | */ | 38 | */ | |
39 | 39 | |||
40 | /* | 40 | /* | |
41 | * Broadcom AirForce BCM43xx IEEE 802.11b/g wireless network driver | 41 | * Broadcom AirForce BCM43xx IEEE 802.11b/g wireless network driver | |
42 | * Generic back end | 42 | * Generic back end | |
43 | */ | 43 | */ | |
44 | 44 | |||
45 | /* [TRC: XXX Names beginning with `bwi_ieee80211_*' are those that I | 45 | /* [TRC: XXX Names beginning with `bwi_ieee80211_*' are those that I | |
46 | think should be in NetBSD's generic 802.11 code, not in this | 46 | think should be in NetBSD's generic 802.11 code, not in this | |
47 | driver.] */ | 47 | driver.] */ | |
48 | 48 | |||
49 | 49 | |||
50 | #include <sys/cdefs.h> | 50 | #include <sys/cdefs.h> | |
51 | __KERNEL_RCSID(0, "$NetBSD: bwi.c,v 1.36 2018/12/22 14:07:53 maxv Exp $"); | 51 | __KERNEL_RCSID(0, "$NetBSD: bwi.c,v 1.37 2020/01/29 14:14:55 thorpej Exp $"); | |
52 | 52 | |||
53 | #include <sys/param.h> | 53 | #include <sys/param.h> | |
54 | #include <sys/callout.h> | 54 | #include <sys/callout.h> | |
55 | #include <sys/device.h> | 55 | #include <sys/device.h> | |
56 | #include <sys/kernel.h> | 56 | #include <sys/kernel.h> | |
57 | #include <sys/malloc.h> | 57 | #include <sys/malloc.h> | |
58 | #include <sys/mbuf.h> | 58 | #include <sys/mbuf.h> | |
59 | #include <sys/socket.h> | 59 | #include <sys/socket.h> | |
60 | #include <sys/sockio.h> | 60 | #include <sys/sockio.h> | |
61 | #include <sys/sysctl.h> | 61 | #include <sys/sysctl.h> | |
62 | #include <sys/systm.h> | 62 | #include <sys/systm.h> | |
63 | #include <sys/bus.h> | 63 | #include <sys/bus.h> | |
64 | #include <sys/intr.h> | 64 | #include <sys/intr.h> | |
65 | 65 | |||
66 | #include <machine/endian.h> | 66 | #include <machine/endian.h> | |
67 | 67 | |||
68 | #include <dev/firmload.h> | 68 | #include <dev/firmload.h> | |
69 | 69 | |||
70 | #include <net/if.h> | 70 | #include <net/if.h> | |
71 | #include <net/if_dl.h> | 71 | #include <net/if_dl.h> | |
72 | #include <net/if_ether.h> | 72 | #include <net/if_ether.h> | |
73 | #include <net/if_media.h> | 73 | #include <net/if_media.h> | |
74 | 74 | |||
75 | #include <net/bpf.h> | 75 | #include <net/bpf.h> | |
76 | 76 | |||
77 | #include <net80211/ieee80211_var.h> | 77 | #include <net80211/ieee80211_var.h> | |
78 | /* [TRC: XXX amrr] */ | 78 | /* [TRC: XXX amrr] */ | |
79 | #include <net80211/ieee80211_amrr.h> | 79 | #include <net80211/ieee80211_amrr.h> | |
80 | #include <net80211/ieee80211_radiotap.h> | 80 | #include <net80211/ieee80211_radiotap.h> | |
81 | 81 | |||
82 | #include <dev/ic/bwireg.h> | 82 | #include <dev/ic/bwireg.h> | |
83 | #include <dev/ic/bwivar.h> | 83 | #include <dev/ic/bwivar.h> | |
84 | 84 | |||
85 | #ifdef BWI_DEBUG | 85 | #ifdef BWI_DEBUG | |
86 | int bwi_debug = 0; | 86 | int bwi_debug = 0; | |
87 | 87 | |||
88 | #define DPRINTF(sc, dbg, fmt, ...) \ | 88 | #define DPRINTF(sc, dbg, fmt, ...) \ | |
89 | do { \ | 89 | do { \ | |
90 | if ((sc)->sc_debug & (dbg)) \ | 90 | if ((sc)->sc_debug & (dbg)) \ | |
91 | aprint_debug_dev((sc)->sc_dev, fmt, ##__VA_ARGS__); \ | 91 | aprint_debug_dev((sc)->sc_dev, fmt, ##__VA_ARGS__); \ | |
92 | } while (0) | 92 | } while (0) | |
93 | 93 | |||
94 | #else /* !BWI_DEBUG */ | 94 | #else /* !BWI_DEBUG */ | |
95 | 95 | |||
96 | #define DPRINTF(sc, dbg, fmt, ...) ((void)0) | 96 | #define DPRINTF(sc, dbg, fmt, ...) ((void)0) | |
97 | 97 | |||
98 | #endif /* BWI_DEBUG */ | 98 | #endif /* BWI_DEBUG */ | |
99 | 99 | |||
100 | /* XXX temporary porting goop */ | 100 | /* XXX temporary porting goop */ | |
101 | #include <dev/pci/pcireg.h> | 101 | #include <dev/pci/pcireg.h> | |
102 | #include <dev/pci/pcivar.h> | 102 | #include <dev/pci/pcivar.h> | |
103 | #include <dev/pci/pcidevs.h> | 103 | #include <dev/pci/pcidevs.h> | |
104 | 104 | |||
105 | /* XXX does not belong here */ | 105 | /* XXX does not belong here */ | |
106 | #define IEEE80211_OFDM_PLCP_RATE_MASK 0x0000000f | 106 | #define IEEE80211_OFDM_PLCP_RATE_MASK 0x0000000f | |
107 | #define IEEE80211_OFDM_PLCP_LEN_MASK 0x0001ffe0 | 107 | #define IEEE80211_OFDM_PLCP_LEN_MASK 0x0001ffe0 | |
108 | 108 | |||
109 | /* | 109 | /* | |
110 | * Contention window (slots). [TRC: dfly/net80211/80211.h] | 110 | * Contention window (slots). [TRC: dfly/net80211/80211.h] | |
111 | */ | 111 | */ | |
112 | #define IEEE80211_CW_MAX 1023 /* aCWmax */ | 112 | #define IEEE80211_CW_MAX 1023 /* aCWmax */ | |
113 | #define IEEE80211_CW_MIN_0 31 /* DS/CCK aCWmin, ERP aCWmin(0) */ | 113 | #define IEEE80211_CW_MIN_0 31 /* DS/CCK aCWmin, ERP aCWmin(0) */ | |
114 | #define IEEE80211_CW_MIN_1 15 /* OFDM aCWmin, ERP aCWmin(1) */ | 114 | #define IEEE80211_CW_MIN_1 15 /* OFDM aCWmin, ERP aCWmin(1) */ | |
115 | 115 | |||
116 | /* | 116 | /* | |
117 | * Slot time (microseconds). [TRC: dfly/net80211/80211.h] | 117 | * Slot time (microseconds). [TRC: dfly/net80211/80211.h] | |
118 | */ | 118 | */ | |
119 | #define IEEE80211_DUR_SLOT 20 /* DS/CCK slottime, ERP long slottime */ | 119 | #define IEEE80211_DUR_SLOT 20 /* DS/CCK slottime, ERP long slottime */ | |
120 | #define IEEE80211_DUR_SHSLOT 9 /* ERP short slottime */ | 120 | #define IEEE80211_DUR_SHSLOT 9 /* ERP short slottime */ | |
121 | #define IEEE80211_DUR_OFDM_SLOT 9 /* OFDM slottime */ | 121 | #define IEEE80211_DUR_OFDM_SLOT 9 /* OFDM slottime */ | |
122 | 122 | |||
123 | /* XXX end porting goop */ | 123 | /* XXX end porting goop */ | |
124 | 124 | |||
125 | /* MAC */ | 125 | /* MAC */ | |
126 | struct bwi_retry_lim { | 126 | struct bwi_retry_lim { | |
127 | uint16_t shretry; | 127 | uint16_t shretry; | |
128 | uint16_t shretry_fb; | 128 | uint16_t shretry_fb; | |
129 | uint16_t lgretry; | 129 | uint16_t lgretry; | |
130 | uint16_t lgretry_fb; | 130 | uint16_t lgretry_fb; | |
131 | }; | 131 | }; | |
132 | 132 | |||
133 | struct bwi_clock_freq { | 133 | struct bwi_clock_freq { | |
134 | uint clkfreq_min; | 134 | uint clkfreq_min; | |
135 | uint clkfreq_max; | 135 | uint clkfreq_max; | |
136 | }; | 136 | }; | |
137 | 137 | |||
138 | /* XXX does not belong here */ | 138 | /* XXX does not belong here */ | |
139 | struct ieee80211_ds_plcp_hdr { | 139 | struct ieee80211_ds_plcp_hdr { | |
140 | uint8_t i_signal; | 140 | uint8_t i_signal; | |
141 | uint8_t i_service; | 141 | uint8_t i_service; | |
142 | uint16_t i_length; | 142 | uint16_t i_length; | |
143 | uint16_t i_crc; | 143 | uint16_t i_crc; | |
144 | } __packed; | 144 | } __packed; | |
145 | 145 | |||
146 | static void bwi_sysctlattach(struct bwi_softc *); | 146 | static void bwi_sysctlattach(struct bwi_softc *); | |
147 | 147 | |||
148 | /* MAC */ | 148 | /* MAC */ | |
149 | static void bwi_tmplt_write_4(struct bwi_mac *, uint32_t, uint32_t); | 149 | static void bwi_tmplt_write_4(struct bwi_mac *, uint32_t, uint32_t); | |
150 | static void bwi_hostflags_write(struct bwi_mac *, uint64_t); | 150 | static void bwi_hostflags_write(struct bwi_mac *, uint64_t); | |
151 | static uint64_t bwi_hostflags_read(struct bwi_mac *); | 151 | static uint64_t bwi_hostflags_read(struct bwi_mac *); | |
152 | static uint16_t bwi_memobj_read_2(struct bwi_mac *, uint16_t, uint16_t); | 152 | static uint16_t bwi_memobj_read_2(struct bwi_mac *, uint16_t, uint16_t); | |
153 | static uint32_t bwi_memobj_read_4(struct bwi_mac *, uint16_t, uint16_t); | 153 | static uint32_t bwi_memobj_read_4(struct bwi_mac *, uint16_t, uint16_t); | |
154 | static void bwi_memobj_write_2(struct bwi_mac *, uint16_t, uint16_t, | 154 | static void bwi_memobj_write_2(struct bwi_mac *, uint16_t, uint16_t, | |
155 | uint16_t); | 155 | uint16_t); | |
156 | static void bwi_memobj_write_4(struct bwi_mac *, uint16_t, uint16_t, | 156 | static void bwi_memobj_write_4(struct bwi_mac *, uint16_t, uint16_t, | |
157 | uint32_t); | 157 | uint32_t); | |
158 | static int bwi_mac_lateattach(struct bwi_mac *); | 158 | static int bwi_mac_lateattach(struct bwi_mac *); | |
159 | static int bwi_mac_init(struct bwi_mac *); | 159 | static int bwi_mac_init(struct bwi_mac *); | |
160 | static void bwi_mac_reset(struct bwi_mac *, int); | 160 | static void bwi_mac_reset(struct bwi_mac *, int); | |
161 | static void bwi_mac_set_tpctl_11bg(struct bwi_mac *, | 161 | static void bwi_mac_set_tpctl_11bg(struct bwi_mac *, | |
162 | const struct bwi_tpctl *); | 162 | const struct bwi_tpctl *); | |
163 | static int bwi_mac_test(struct bwi_mac *); | 163 | static int bwi_mac_test(struct bwi_mac *); | |
164 | static void bwi_mac_setup_tpctl(struct bwi_mac *); | 164 | static void bwi_mac_setup_tpctl(struct bwi_mac *); | |
165 | static void bwi_mac_dummy_xmit(struct bwi_mac *); | 165 | static void bwi_mac_dummy_xmit(struct bwi_mac *); | |
166 | static void bwi_mac_init_tpctl_11bg(struct bwi_mac *); | 166 | static void bwi_mac_init_tpctl_11bg(struct bwi_mac *); | |
167 | static void bwi_mac_detach(struct bwi_mac *); | 167 | static void bwi_mac_detach(struct bwi_mac *); | |
168 | static int bwi_mac_fw_alloc(struct bwi_mac *); | 168 | static int bwi_mac_fw_alloc(struct bwi_mac *); | |
169 | static void bwi_mac_fw_free(struct bwi_mac *); | 169 | static void bwi_mac_fw_free(struct bwi_mac *); | |
170 | static int bwi_mac_fw_image_alloc(struct bwi_mac *, const char *, | 170 | static int bwi_mac_fw_image_alloc(struct bwi_mac *, const char *, | |
171 | int idx, struct bwi_fw_image *, uint8_t); | 171 | int idx, struct bwi_fw_image *, uint8_t); | |
172 | static void bwi_mac_fw_image_free(struct bwi_mac *, struct bwi_fw_image *); | 172 | static void bwi_mac_fw_image_free(struct bwi_mac *, struct bwi_fw_image *); | |
173 | static int bwi_mac_fw_load(struct bwi_mac *); | 173 | static int bwi_mac_fw_load(struct bwi_mac *); | |
174 | static int bwi_mac_gpio_init(struct bwi_mac *); | 174 | static int bwi_mac_gpio_init(struct bwi_mac *); | |
175 | static int bwi_mac_gpio_fini(struct bwi_mac *); | 175 | static int bwi_mac_gpio_fini(struct bwi_mac *); | |
176 | static int bwi_mac_fw_load_iv(struct bwi_mac *, | 176 | static int bwi_mac_fw_load_iv(struct bwi_mac *, | |
177 | const struct bwi_fw_image *); | 177 | const struct bwi_fw_image *); | |
178 | static int bwi_mac_fw_init(struct bwi_mac *); | 178 | static int bwi_mac_fw_init(struct bwi_mac *); | |
179 | static void bwi_mac_opmode_init(struct bwi_mac *); | 179 | static void bwi_mac_opmode_init(struct bwi_mac *); | |
180 | static void bwi_mac_hostflags_init(struct bwi_mac *); | 180 | static void bwi_mac_hostflags_init(struct bwi_mac *); | |
181 | static void bwi_mac_bss_param_init(struct bwi_mac *); | 181 | static void bwi_mac_bss_param_init(struct bwi_mac *); | |
182 | static void bwi_mac_set_retry_lim(struct bwi_mac *, | 182 | static void bwi_mac_set_retry_lim(struct bwi_mac *, | |
183 | const struct bwi_retry_lim *); | 183 | const struct bwi_retry_lim *); | |
184 | static void bwi_mac_set_ackrates(struct bwi_mac *, | 184 | static void bwi_mac_set_ackrates(struct bwi_mac *, | |
185 | const struct ieee80211_rateset *); | 185 | const struct ieee80211_rateset *); | |
186 | static int bwi_mac_start(struct bwi_mac *); | 186 | static int bwi_mac_start(struct bwi_mac *); | |
187 | static int bwi_mac_stop(struct bwi_mac *); | 187 | static int bwi_mac_stop(struct bwi_mac *); | |
188 | static int bwi_mac_config_ps(struct bwi_mac *); | 188 | static int bwi_mac_config_ps(struct bwi_mac *); | |
189 | static void bwi_mac_reset_hwkeys(struct bwi_mac *); | 189 | static void bwi_mac_reset_hwkeys(struct bwi_mac *); | |
190 | static void bwi_mac_shutdown(struct bwi_mac *); | 190 | static void bwi_mac_shutdown(struct bwi_mac *); | |
191 | static int bwi_mac_get_property(struct bwi_mac *); | 191 | static int bwi_mac_get_property(struct bwi_mac *); | |
192 | static void bwi_mac_updateslot(struct bwi_mac *, int); | 192 | static void bwi_mac_updateslot(struct bwi_mac *, int); | |
193 | static int bwi_mac_attach(struct bwi_softc *, int, uint8_t); | 193 | static int bwi_mac_attach(struct bwi_softc *, int, uint8_t); | |
194 | static void bwi_mac_balance_atten(int *, int *); | 194 | static void bwi_mac_balance_atten(int *, int *); | |
195 | static void bwi_mac_adjust_tpctl(struct bwi_mac *, int, int); | 195 | static void bwi_mac_adjust_tpctl(struct bwi_mac *, int, int); | |
196 | static void bwi_mac_calibrate_txpower(struct bwi_mac *, | 196 | static void bwi_mac_calibrate_txpower(struct bwi_mac *, | |
197 | enum bwi_txpwrcb_type); | 197 | enum bwi_txpwrcb_type); | |
198 | static void bwi_mac_lock(struct bwi_mac *); | 198 | static void bwi_mac_lock(struct bwi_mac *); | |
199 | static void bwi_mac_unlock(struct bwi_mac *); | 199 | static void bwi_mac_unlock(struct bwi_mac *); | |
200 | static void bwi_mac_set_promisc(struct bwi_mac *, int); | 200 | static void bwi_mac_set_promisc(struct bwi_mac *, int); | |
201 | 201 | |||
202 | /* PHY */ | 202 | /* PHY */ | |
203 | static void bwi_phy_write(struct bwi_mac *, uint16_t, uint16_t); | 203 | static void bwi_phy_write(struct bwi_mac *, uint16_t, uint16_t); | |
204 | static uint16_t bwi_phy_read(struct bwi_mac *, uint16_t); | 204 | static uint16_t bwi_phy_read(struct bwi_mac *, uint16_t); | |
205 | static int bwi_phy_attach(struct bwi_mac *); | 205 | static int bwi_phy_attach(struct bwi_mac *); | |
206 | static void bwi_phy_set_bbp_atten(struct bwi_mac *, uint16_t); | 206 | static void bwi_phy_set_bbp_atten(struct bwi_mac *, uint16_t); | |
207 | static int bwi_phy_calibrate(struct bwi_mac *); | 207 | static int bwi_phy_calibrate(struct bwi_mac *); | |
208 | static void bwi_tbl_write_2(struct bwi_mac *mac, uint16_t, uint16_t); | 208 | static void bwi_tbl_write_2(struct bwi_mac *mac, uint16_t, uint16_t); | |
209 | static void bwi_tbl_write_4(struct bwi_mac *mac, uint16_t, uint32_t); | 209 | static void bwi_tbl_write_4(struct bwi_mac *mac, uint16_t, uint32_t); | |
210 | static void bwi_nrssi_write(struct bwi_mac *, uint16_t, int16_t); | 210 | static void bwi_nrssi_write(struct bwi_mac *, uint16_t, int16_t); | |
211 | static int16_t bwi_nrssi_read(struct bwi_mac *, uint16_t); | 211 | static int16_t bwi_nrssi_read(struct bwi_mac *, uint16_t); | |
212 | static void bwi_phy_init_11a(struct bwi_mac *); | 212 | static void bwi_phy_init_11a(struct bwi_mac *); | |
213 | static void bwi_phy_init_11g(struct bwi_mac *); | 213 | static void bwi_phy_init_11g(struct bwi_mac *); | |
214 | static void bwi_phy_init_11b_rev2(struct bwi_mac *); | 214 | static void bwi_phy_init_11b_rev2(struct bwi_mac *); | |
215 | static void bwi_phy_init_11b_rev4(struct bwi_mac *); | 215 | static void bwi_phy_init_11b_rev4(struct bwi_mac *); | |
216 | static void bwi_phy_init_11b_rev5(struct bwi_mac *); | 216 | static void bwi_phy_init_11b_rev5(struct bwi_mac *); | |
217 | static void bwi_phy_init_11b_rev6(struct bwi_mac *); | 217 | static void bwi_phy_init_11b_rev6(struct bwi_mac *); | |
218 | static void bwi_phy_config_11g(struct bwi_mac *); | 218 | static void bwi_phy_config_11g(struct bwi_mac *); | |
219 | static void bwi_phy_config_agc(struct bwi_mac *); | 219 | static void bwi_phy_config_agc(struct bwi_mac *); | |
220 | static void bwi_set_gains(struct bwi_mac *, const struct bwi_gains *); | 220 | static void bwi_set_gains(struct bwi_mac *, const struct bwi_gains *); | |
221 | static void bwi_phy_clear_state(struct bwi_phy *); | 221 | static void bwi_phy_clear_state(struct bwi_phy *); | |
222 | 222 | |||
223 | /* RF */ | 223 | /* RF */ | |
224 | static int16_t bwi_nrssi_11g(struct bwi_mac *); | 224 | static int16_t bwi_nrssi_11g(struct bwi_mac *); | |
225 | static struct bwi_rf_lo | 225 | static struct bwi_rf_lo | |
226 | *bwi_get_rf_lo(struct bwi_mac *, uint16_t, uint16_t); | 226 | *bwi_get_rf_lo(struct bwi_mac *, uint16_t, uint16_t); | |
227 | static int bwi_rf_lo_isused(struct bwi_mac *, const struct bwi_rf_lo *); | 227 | static int bwi_rf_lo_isused(struct bwi_mac *, const struct bwi_rf_lo *); | |
228 | static void bwi_rf_write(struct bwi_mac *, uint16_t, uint16_t); | 228 | static void bwi_rf_write(struct bwi_mac *, uint16_t, uint16_t); | |
229 | static uint16_t bwi_rf_read(struct bwi_mac *, uint16_t); | 229 | static uint16_t bwi_rf_read(struct bwi_mac *, uint16_t); | |
230 | static int bwi_rf_attach(struct bwi_mac *); | 230 | static int bwi_rf_attach(struct bwi_mac *); | |
231 | static void bwi_rf_set_chan(struct bwi_mac *, uint, int); | 231 | static void bwi_rf_set_chan(struct bwi_mac *, uint, int); | |
232 | static void bwi_rf_get_gains(struct bwi_mac *); | 232 | static void bwi_rf_get_gains(struct bwi_mac *); | |
233 | static void bwi_rf_init(struct bwi_mac *); | 233 | static void bwi_rf_init(struct bwi_mac *); | |
234 | static void bwi_rf_off_11a(struct bwi_mac *); | 234 | static void bwi_rf_off_11a(struct bwi_mac *); | |
235 | static void bwi_rf_off_11bg(struct bwi_mac *); | 235 | static void bwi_rf_off_11bg(struct bwi_mac *); | |
236 | static void bwi_rf_off_11g_rev5(struct bwi_mac *); | 236 | static void bwi_rf_off_11g_rev5(struct bwi_mac *); | |
237 | static void bwi_rf_workaround(struct bwi_mac *, uint); | 237 | static void bwi_rf_workaround(struct bwi_mac *, uint); | |
238 | static struct bwi_rf_lo | 238 | static struct bwi_rf_lo | |
239 | *bwi_rf_lo_find(struct bwi_mac *, const struct bwi_tpctl *); | 239 | *bwi_rf_lo_find(struct bwi_mac *, const struct bwi_tpctl *); | |
240 | static void bwi_rf_lo_adjust(struct bwi_mac *, const struct bwi_tpctl *); | 240 | static void bwi_rf_lo_adjust(struct bwi_mac *, const struct bwi_tpctl *); | |
241 | static void bwi_rf_lo_write(struct bwi_mac *, const struct bwi_rf_lo *); | 241 | static void bwi_rf_lo_write(struct bwi_mac *, const struct bwi_rf_lo *); | |
242 | static int bwi_rf_gain_max_reached(struct bwi_mac *, int); | 242 | static int bwi_rf_gain_max_reached(struct bwi_mac *, int); | |
243 | static uint16_t bwi_bitswap4(uint16_t); | 243 | static uint16_t bwi_bitswap4(uint16_t); | |
244 | static uint16_t bwi_phy812_value(struct bwi_mac *, uint16_t); | 244 | static uint16_t bwi_phy812_value(struct bwi_mac *, uint16_t); | |
245 | static void bwi_rf_init_bcm2050(struct bwi_mac *); | 245 | static void bwi_rf_init_bcm2050(struct bwi_mac *); | |
246 | static uint16_t bwi_rf_calibval(struct bwi_mac *); | 246 | static uint16_t bwi_rf_calibval(struct bwi_mac *); | |
247 | static int32_t _bwi_adjust_devide(int32_t, int32_t); | 247 | static int32_t _bwi_adjust_devide(int32_t, int32_t); | |
248 | static int bwi_rf_calc_txpower(int8_t *, uint8_t, const int16_t[]); | 248 | static int bwi_rf_calc_txpower(int8_t *, uint8_t, const int16_t[]); | |
249 | static int bwi_rf_map_txpower(struct bwi_mac *); | 249 | static int bwi_rf_map_txpower(struct bwi_mac *); | |
250 | static void bwi_rf_lo_update_11g(struct bwi_mac *); | 250 | static void bwi_rf_lo_update_11g(struct bwi_mac *); | |
251 | static uint32_t bwi_rf_lo_devi_measure(struct bwi_mac *, uint16_t); | 251 | static uint32_t bwi_rf_lo_devi_measure(struct bwi_mac *, uint16_t); | |
252 | static uint16_t bwi_rf_get_tp_ctrl2(struct bwi_mac *); | 252 | static uint16_t bwi_rf_get_tp_ctrl2(struct bwi_mac *); | |
253 | static uint8_t _bwi_rf_lo_update_11g(struct bwi_mac *, uint16_t); | 253 | static uint8_t _bwi_rf_lo_update_11g(struct bwi_mac *, uint16_t); | |
254 | static void bwi_rf_lo_measure_11g(struct bwi_mac *, | 254 | static void bwi_rf_lo_measure_11g(struct bwi_mac *, | |
255 | const struct bwi_rf_lo *, struct bwi_rf_lo *, uint8_t); | 255 | const struct bwi_rf_lo *, struct bwi_rf_lo *, uint8_t); | |
256 | static void bwi_rf_calc_nrssi_slope_11b(struct bwi_mac *); | 256 | static void bwi_rf_calc_nrssi_slope_11b(struct bwi_mac *); | |
257 | static void bwi_rf_set_nrssi_ofs_11g(struct bwi_mac *); | 257 | static void bwi_rf_set_nrssi_ofs_11g(struct bwi_mac *); | |
258 | static void bwi_rf_calc_nrssi_slope_11g(struct bwi_mac *); | 258 | static void bwi_rf_calc_nrssi_slope_11g(struct bwi_mac *); | |
259 | static void bwi_rf_init_sw_nrssi_table(struct bwi_mac *); | 259 | static void bwi_rf_init_sw_nrssi_table(struct bwi_mac *); | |
260 | static void bwi_rf_init_hw_nrssi_table(struct bwi_mac *, uint16_t); | 260 | static void bwi_rf_init_hw_nrssi_table(struct bwi_mac *, uint16_t); | |
261 | static void bwi_rf_set_nrssi_thr_11b(struct bwi_mac *); | 261 | static void bwi_rf_set_nrssi_thr_11b(struct bwi_mac *); | |
262 | static int32_t _nrssi_threshold(const struct bwi_rf *, int32_t); | 262 | static int32_t _nrssi_threshold(const struct bwi_rf *, int32_t); | |
263 | static void bwi_rf_set_nrssi_thr_11g(struct bwi_mac *); | 263 | static void bwi_rf_set_nrssi_thr_11g(struct bwi_mac *); | |
264 | static void bwi_rf_clear_tssi(struct bwi_mac *); | 264 | static void bwi_rf_clear_tssi(struct bwi_mac *); | |
265 | static void bwi_rf_clear_state(struct bwi_rf *); | 265 | static void bwi_rf_clear_state(struct bwi_rf *); | |
266 | static void bwi_rf_on_11a(struct bwi_mac *); | 266 | static void bwi_rf_on_11a(struct bwi_mac *); | |
267 | static void bwi_rf_on_11bg(struct bwi_mac *); | 267 | static void bwi_rf_on_11bg(struct bwi_mac *); | |
268 | static void bwi_rf_set_ant_mode(struct bwi_mac *, int); | 268 | static void bwi_rf_set_ant_mode(struct bwi_mac *, int); | |
269 | static int bwi_rf_get_latest_tssi(struct bwi_mac *, int8_t[], uint16_t); | 269 | static int bwi_rf_get_latest_tssi(struct bwi_mac *, int8_t[], uint16_t); | |
270 | static int bwi_rf_tssi2dbm(struct bwi_mac *, int8_t, int8_t *); | 270 | static int bwi_rf_tssi2dbm(struct bwi_mac *, int8_t, int8_t *); | |
271 | static int bwi_rf_calc_rssi_bcm2050(struct bwi_mac *, | 271 | static int bwi_rf_calc_rssi_bcm2050(struct bwi_mac *, | |
272 | const struct bwi_rxbuf_hdr *); | 272 | const struct bwi_rxbuf_hdr *); | |
273 | static int bwi_rf_calc_rssi_bcm2053(struct bwi_mac *, | 273 | static int bwi_rf_calc_rssi_bcm2053(struct bwi_mac *, | |
274 | const struct bwi_rxbuf_hdr *); | 274 | const struct bwi_rxbuf_hdr *); | |
275 | static int bwi_rf_calc_rssi_bcm2060(struct bwi_mac *, | 275 | static int bwi_rf_calc_rssi_bcm2060(struct bwi_mac *, | |
276 | const struct bwi_rxbuf_hdr *); | 276 | const struct bwi_rxbuf_hdr *); | |
277 | static uint16_t bwi_rf_lo_measure_11b(struct bwi_mac *); | 277 | static uint16_t bwi_rf_lo_measure_11b(struct bwi_mac *); | |
278 | static void bwi_rf_lo_update_11b(struct bwi_mac *); | 278 | static void bwi_rf_lo_update_11b(struct bwi_mac *); | |
279 | 279 | |||
280 | /* INTERFACE */ | 280 | /* INTERFACE */ | |
281 | static uint16_t bwi_read_sprom(struct bwi_softc *, uint16_t); | 281 | static uint16_t bwi_read_sprom(struct bwi_softc *, uint16_t); | |
282 | static void bwi_setup_desc32(struct bwi_softc *, struct bwi_desc32 *, int, | 282 | static void bwi_setup_desc32(struct bwi_softc *, struct bwi_desc32 *, int, | |
283 | int, bus_addr_t, int, int); | 283 | int, bus_addr_t, int, int); | |
284 | static void bwi_power_on(struct bwi_softc *, int); | 284 | static void bwi_power_on(struct bwi_softc *, int); | |
285 | static int bwi_power_off(struct bwi_softc *, int); | 285 | static int bwi_power_off(struct bwi_softc *, int); | |
286 | static int bwi_regwin_switch(struct bwi_softc *, struct bwi_regwin *, | 286 | static int bwi_regwin_switch(struct bwi_softc *, struct bwi_regwin *, | |
287 | struct bwi_regwin **); | 287 | struct bwi_regwin **); | |
288 | static int bwi_regwin_select(struct bwi_softc *, int); | 288 | static int bwi_regwin_select(struct bwi_softc *, int); | |
289 | static void bwi_regwin_info(struct bwi_softc *, uint16_t *, uint8_t *); | 289 | static void bwi_regwin_info(struct bwi_softc *, uint16_t *, uint8_t *); | |
290 | static void bwi_led_attach(struct bwi_softc *); | 290 | static void bwi_led_attach(struct bwi_softc *); | |
291 | static void bwi_led_newstate(struct bwi_softc *, enum ieee80211_state); | 291 | static void bwi_led_newstate(struct bwi_softc *, enum ieee80211_state); | |
292 | static uint16_t bwi_led_onoff(const struct bwi_led *, uint16_t, int); | 292 | static uint16_t bwi_led_onoff(const struct bwi_led *, uint16_t, int); | |
293 | static void bwi_led_event(struct bwi_softc *, int); | 293 | static void bwi_led_event(struct bwi_softc *, int); | |
294 | static void bwi_led_blink_start(struct bwi_softc *, int, int); | 294 | static void bwi_led_blink_start(struct bwi_softc *, int, int); | |
295 | static void bwi_led_blink_next(void *); | 295 | static void bwi_led_blink_next(void *); | |
296 | static void bwi_led_blink_end(void *); | 296 | static void bwi_led_blink_end(void *); | |
297 | static int bwi_bbp_attach(struct bwi_softc *); | 297 | static int bwi_bbp_attach(struct bwi_softc *); | |
298 | static int bwi_bus_init(struct bwi_softc *, struct bwi_mac *); | 298 | static int bwi_bus_init(struct bwi_softc *, struct bwi_mac *); | |
299 | static void bwi_get_card_flags(struct bwi_softc *); | 299 | static void bwi_get_card_flags(struct bwi_softc *); | |
300 | static void bwi_get_eaddr(struct bwi_softc *, uint16_t, uint8_t *); | 300 | static void bwi_get_eaddr(struct bwi_softc *, uint16_t, uint8_t *); | |
301 | static void bwi_get_clock_freq(struct bwi_softc *, | 301 | static void bwi_get_clock_freq(struct bwi_softc *, | |
302 | struct bwi_clock_freq *); | 302 | struct bwi_clock_freq *); | |
303 | static int bwi_set_clock_mode(struct bwi_softc *, enum bwi_clock_mode); | 303 | static int bwi_set_clock_mode(struct bwi_softc *, enum bwi_clock_mode); | |
304 | static int bwi_set_clock_delay(struct bwi_softc *); | 304 | static int bwi_set_clock_delay(struct bwi_softc *); | |
305 | static int bwi_init(struct ifnet *); | 305 | static int bwi_init(struct ifnet *); | |
306 | static void bwi_init_statechg(struct bwi_softc *, int); | 306 | static void bwi_init_statechg(struct bwi_softc *, int); | |
307 | static int bwi_ioctl(struct ifnet *, u_long, void *); | 307 | static int bwi_ioctl(struct ifnet *, u_long, void *); | |
308 | static void bwi_start(struct ifnet *); | 308 | static void bwi_start(struct ifnet *); | |
309 | static void bwi_watchdog(struct ifnet *); | 309 | static void bwi_watchdog(struct ifnet *); | |
310 | static void bwi_stop(struct ifnet *, int); | 310 | static void bwi_stop(struct ifnet *, int); | |
311 | static void bwi_newstate_begin(struct bwi_softc *, enum ieee80211_state); | 311 | static void bwi_newstate_begin(struct bwi_softc *, enum ieee80211_state); | |
312 | static int bwi_newstate(struct ieee80211com *, enum ieee80211_state, int); | 312 | static int bwi_newstate(struct ieee80211com *, enum ieee80211_state, int); | |
313 | static int bwi_media_change(struct ifnet *); | 313 | static int bwi_media_change(struct ifnet *); | |
314 | /* [TRC: XXX amrr] */ | 314 | /* [TRC: XXX amrr] */ | |
315 | static void bwi_iter_func(void *, struct ieee80211_node *); | 315 | static void bwi_iter_func(void *, struct ieee80211_node *); | |
316 | static void bwi_amrr_timeout(void *); | 316 | static void bwi_amrr_timeout(void *); | |
317 | static void bwi_newassoc(struct ieee80211_node *, int); | 317 | static void bwi_newassoc(struct ieee80211_node *, int); | |
318 | static struct ieee80211_node * | 318 | static struct ieee80211_node * | |
319 | bwi_node_alloc(struct ieee80211_node_table *); | 319 | bwi_node_alloc(struct ieee80211_node_table *); | |
320 | static int bwi_dma_alloc(struct bwi_softc *); | 320 | static int bwi_dma_alloc(struct bwi_softc *); | |
321 | static void bwi_dma_free(struct bwi_softc *); | 321 | static void bwi_dma_free(struct bwi_softc *); | |
322 | static void bwi_ring_data_free(struct bwi_ring_data *, struct bwi_softc *); | 322 | static void bwi_ring_data_free(struct bwi_ring_data *, struct bwi_softc *); | |
323 | static int bwi_dma_ring_alloc(struct bwi_softc *, | 323 | static int bwi_dma_ring_alloc(struct bwi_softc *, | |
324 | struct bwi_ring_data *, bus_size_t, uint32_t); | 324 | struct bwi_ring_data *, bus_size_t, uint32_t); | |
325 | static int bwi_dma_txstats_alloc(struct bwi_softc *, uint32_t, | 325 | static int bwi_dma_txstats_alloc(struct bwi_softc *, uint32_t, | |
326 | bus_size_t); | 326 | bus_size_t); | |
327 | static void bwi_dma_txstats_free(struct bwi_softc *); | 327 | static void bwi_dma_txstats_free(struct bwi_softc *); | |
328 | static int bwi_dma_mbuf_create(struct bwi_softc *); | 328 | static int bwi_dma_mbuf_create(struct bwi_softc *); | |
329 | static void bwi_dma_mbuf_destroy(struct bwi_softc *, int, int); | 329 | static void bwi_dma_mbuf_destroy(struct bwi_softc *, int, int); | |
330 | static void bwi_enable_intrs(struct bwi_softc *, uint32_t); | 330 | static void bwi_enable_intrs(struct bwi_softc *, uint32_t); | |
331 | static void bwi_disable_intrs(struct bwi_softc *, uint32_t); | 331 | static void bwi_disable_intrs(struct bwi_softc *, uint32_t); | |
332 | static int bwi_init_tx_ring32(struct bwi_softc *, int); | 332 | static int bwi_init_tx_ring32(struct bwi_softc *, int); | |
333 | static void bwi_init_rxdesc_ring32(struct bwi_softc *, uint32_t, | 333 | static void bwi_init_rxdesc_ring32(struct bwi_softc *, uint32_t, | |
334 | bus_addr_t, int, int); | 334 | bus_addr_t, int, int); | |
335 | static int bwi_init_rx_ring32(struct bwi_softc *); | 335 | static int bwi_init_rx_ring32(struct bwi_softc *); | |
336 | static int bwi_init_txstats32(struct bwi_softc *); | 336 | static int bwi_init_txstats32(struct bwi_softc *); | |
337 | static void bwi_setup_rx_desc32(struct bwi_softc *, int, bus_addr_t, int); | 337 | static void bwi_setup_rx_desc32(struct bwi_softc *, int, bus_addr_t, int); | |
338 | static void bwi_setup_tx_desc32(struct bwi_softc *, struct bwi_ring_data *, | 338 | static void bwi_setup_tx_desc32(struct bwi_softc *, struct bwi_ring_data *, | |
339 | int, bus_addr_t, int); | 339 | int, bus_addr_t, int); | |
340 | static int bwi_init_tx_ring64(struct bwi_softc *, int); | 340 | static int bwi_init_tx_ring64(struct bwi_softc *, int); | |
341 | static int bwi_init_rx_ring64(struct bwi_softc *); | 341 | static int bwi_init_rx_ring64(struct bwi_softc *); | |
342 | static int bwi_init_txstats64(struct bwi_softc *); | 342 | static int bwi_init_txstats64(struct bwi_softc *); | |
343 | static void bwi_setup_rx_desc64(struct bwi_softc *, int, bus_addr_t, int); | 343 | static void bwi_setup_rx_desc64(struct bwi_softc *, int, bus_addr_t, int); | |
344 | static void bwi_setup_tx_desc64(struct bwi_softc *, struct bwi_ring_data *, | 344 | static void bwi_setup_tx_desc64(struct bwi_softc *, struct bwi_ring_data *, | |
345 | int, bus_addr_t, int); | 345 | int, bus_addr_t, int); | |
346 | static int bwi_newbuf(struct bwi_softc *, int, int); | 346 | static int bwi_newbuf(struct bwi_softc *, int, int); | |
347 | static void bwi_set_addr_filter(struct bwi_softc *, uint16_t, | 347 | static void bwi_set_addr_filter(struct bwi_softc *, uint16_t, | |
348 | const uint8_t *); | 348 | const uint8_t *); | |
349 | static int bwi_set_chan(struct bwi_softc *, struct ieee80211_channel *); | 349 | static int bwi_set_chan(struct bwi_softc *, struct ieee80211_channel *); | |
350 | static void bwi_next_scan(void *); | 350 | static void bwi_next_scan(void *); | |
351 | static int bwi_rxeof(struct bwi_softc *, int); | 351 | static int bwi_rxeof(struct bwi_softc *, int); | |
352 | static int bwi_rxeof32(struct bwi_softc *); | 352 | static int bwi_rxeof32(struct bwi_softc *); | |
353 | static int bwi_rxeof64(struct bwi_softc *); | 353 | static int bwi_rxeof64(struct bwi_softc *); | |
354 | static void bwi_reset_rx_ring32(struct bwi_softc *, uint32_t); | 354 | static void bwi_reset_rx_ring32(struct bwi_softc *, uint32_t); | |
355 | static void bwi_free_txstats32(struct bwi_softc *); | 355 | static void bwi_free_txstats32(struct bwi_softc *); | |
356 | static void bwi_free_rx_ring32(struct bwi_softc *); | 356 | static void bwi_free_rx_ring32(struct bwi_softc *); | |
357 | static void bwi_free_tx_ring32(struct bwi_softc *, int); | 357 | static void bwi_free_tx_ring32(struct bwi_softc *, int); | |
358 | static void bwi_free_txstats64(struct bwi_softc *); | 358 | static void bwi_free_txstats64(struct bwi_softc *); | |
359 | static void bwi_free_rx_ring64(struct bwi_softc *); | 359 | static void bwi_free_rx_ring64(struct bwi_softc *); | |
360 | static void bwi_free_tx_ring64(struct bwi_softc *, int); | 360 | static void bwi_free_tx_ring64(struct bwi_softc *, int); | |
361 | static uint8_t bwi_ieee80211_rate2plcp(uint8_t rate, enum ieee80211_phymode); | 361 | static uint8_t bwi_ieee80211_rate2plcp(uint8_t rate, enum ieee80211_phymode); | |
362 | static uint8_t bwi_ieee80211_plcp2rate(uint8_t rate, enum ieee80211_phymode); | 362 | static uint8_t bwi_ieee80211_plcp2rate(uint8_t rate, enum ieee80211_phymode); | |
363 | static enum bwi_ieee80211_modtype | 363 | static enum bwi_ieee80211_modtype | |
364 | bwi_ieee80211_rate2modtype(uint8_t rate); | 364 | bwi_ieee80211_rate2modtype(uint8_t rate); | |
365 | static uint8_t bwi_ofdm_plcp2rate(const void *); | 365 | static uint8_t bwi_ofdm_plcp2rate(const void *); | |
366 | static uint8_t bwi_ds_plcp2rate(const struct ieee80211_ds_plcp_hdr *); | 366 | static uint8_t bwi_ds_plcp2rate(const struct ieee80211_ds_plcp_hdr *); | |
367 | static void bwi_ofdm_plcp_header(uint32_t *, int, uint8_t); | 367 | static void bwi_ofdm_plcp_header(uint32_t *, int, uint8_t); | |
368 | static void bwi_ds_plcp_header(struct ieee80211_ds_plcp_hdr *, int, | 368 | static void bwi_ds_plcp_header(struct ieee80211_ds_plcp_hdr *, int, | |
369 | uint8_t); | 369 | uint8_t); | |
370 | static void bwi_plcp_header(void *, int, uint8_t); | 370 | static void bwi_plcp_header(void *, int, uint8_t); | |
371 | static int bwi_encap(struct bwi_softc *, int, struct mbuf *, | 371 | static int bwi_encap(struct bwi_softc *, int, struct mbuf *, | |
372 | struct ieee80211_node **, int); | 372 | struct ieee80211_node **, int); | |
373 | static void bwi_start_tx32(struct bwi_softc *, uint32_t, int); | 373 | static void bwi_start_tx32(struct bwi_softc *, uint32_t, int); | |
374 | static void bwi_start_tx64(struct bwi_softc *, uint32_t, int); | 374 | static void bwi_start_tx64(struct bwi_softc *, uint32_t, int); | |
375 | static void bwi_txeof_status32(struct bwi_softc *); | 375 | static void bwi_txeof_status32(struct bwi_softc *); | |
376 | static void bwi_txeof_status64(struct bwi_softc *); | 376 | static void bwi_txeof_status64(struct bwi_softc *); | |
377 | static void _bwi_txeof(struct bwi_softc *, uint16_t); | 377 | static void _bwi_txeof(struct bwi_softc *, uint16_t); | |
378 | static void bwi_txeof_status(struct bwi_softc *, int); | 378 | static void bwi_txeof_status(struct bwi_softc *, int); | |
379 | static void bwi_txeof(struct bwi_softc *); | 379 | static void bwi_txeof(struct bwi_softc *); | |
380 | static int bwi_bbp_power_on(struct bwi_softc *, enum bwi_clock_mode); | 380 | static int bwi_bbp_power_on(struct bwi_softc *, enum bwi_clock_mode); | |
381 | static void bwi_bbp_power_off(struct bwi_softc *); | 381 | static void bwi_bbp_power_off(struct bwi_softc *); | |
382 | static int bwi_get_pwron_delay(struct bwi_softc *sc); | 382 | static int bwi_get_pwron_delay(struct bwi_softc *sc); | |
383 | static int bwi_bus_attach(struct bwi_softc *); | 383 | static int bwi_bus_attach(struct bwi_softc *); | |
384 | static const char | 384 | static const char | |
385 | *bwi_regwin_name(const struct bwi_regwin *); | 385 | *bwi_regwin_name(const struct bwi_regwin *); | |
386 | static int bwi_regwin_is_enabled(struct bwi_softc *, struct bwi_regwin *); | 386 | static int bwi_regwin_is_enabled(struct bwi_softc *, struct bwi_regwin *); | |
387 | static uint32_t bwi_regwin_disable_bits(struct bwi_softc *); | 387 | static uint32_t bwi_regwin_disable_bits(struct bwi_softc *); | |
388 | static void bwi_regwin_enable(struct bwi_softc *, struct bwi_regwin *, | 388 | static void bwi_regwin_enable(struct bwi_softc *, struct bwi_regwin *, | |
389 | uint32_t); | 389 | uint32_t); | |
390 | static void bwi_regwin_disable(struct bwi_softc *, struct bwi_regwin *, | 390 | static void bwi_regwin_disable(struct bwi_softc *, struct bwi_regwin *, | |
391 | uint32_t); | 391 | uint32_t); | |
392 | static void bwi_set_bssid(struct bwi_softc *, const uint8_t *); | 392 | static void bwi_set_bssid(struct bwi_softc *, const uint8_t *); | |
393 | static void bwi_updateslot(struct ifnet *); | 393 | static void bwi_updateslot(struct ifnet *); | |
394 | static void bwi_calibrate(void *); | 394 | static void bwi_calibrate(void *); | |
395 | static int bwi_calc_rssi(struct bwi_softc *, | 395 | static int bwi_calc_rssi(struct bwi_softc *, | |
396 | const struct bwi_rxbuf_hdr *); | 396 | const struct bwi_rxbuf_hdr *); | |
397 | static uint8_t bwi_ieee80211_ack_rate(struct ieee80211_node *, uint8_t); | 397 | static uint8_t bwi_ieee80211_ack_rate(struct ieee80211_node *, uint8_t); | |
398 | static uint16_t bwi_ieee80211_txtime(struct ieee80211com *, | 398 | static uint16_t bwi_ieee80211_txtime(struct ieee80211com *, | |
399 | struct ieee80211_node *, uint, uint8_t, uint32_t); | 399 | struct ieee80211_node *, uint, uint8_t, uint32_t); | |
400 | 400 | |||
401 | /* MAC */ | 401 | /* MAC */ | |
402 | static const uint8_t bwi_sup_macrev[] = { 2, 4, 5, 6, 7, 9, 10, 12 }; | 402 | static const uint8_t bwi_sup_macrev[] = { 2, 4, 5, 6, 7, 9, 10, 12 }; | |
403 | 403 | |||
404 | /* PHY */ | 404 | /* PHY */ | |
405 | #define SUP_BPHY(num) { .rev = num, .init = bwi_phy_init_11b_rev##num } | 405 | #define SUP_BPHY(num) { .rev = num, .init = bwi_phy_init_11b_rev##num } | |
406 | 406 | |||
407 | static const struct { | 407 | static const struct { | |
408 | uint8_t rev; | 408 | uint8_t rev; | |
409 | void (*init)(struct bwi_mac *); | 409 | void (*init)(struct bwi_mac *); | |
410 | } bwi_sup_bphy[] = { | 410 | } bwi_sup_bphy[] = { | |
411 | SUP_BPHY(2), | 411 | SUP_BPHY(2), | |
412 | SUP_BPHY(4), | 412 | SUP_BPHY(4), | |
413 | SUP_BPHY(5), | 413 | SUP_BPHY(5), | |
414 | SUP_BPHY(6) | 414 | SUP_BPHY(6) | |
415 | }; | 415 | }; | |
416 | 416 | |||
417 | #undef SUP_BPHY | 417 | #undef SUP_BPHY | |
418 | 418 | |||
419 | #define BWI_PHYTBL_WRSSI 0x1000 | 419 | #define BWI_PHYTBL_WRSSI 0x1000 | |
420 | #define BWI_PHYTBL_NOISE_SCALE 0x1400 | 420 | #define BWI_PHYTBL_NOISE_SCALE 0x1400 | |
421 | #define BWI_PHYTBL_NOISE 0x1800 | 421 | #define BWI_PHYTBL_NOISE 0x1800 | |
422 | #define BWI_PHYTBL_ROTOR 0x2000 | 422 | #define BWI_PHYTBL_ROTOR 0x2000 | |
423 | #define BWI_PHYTBL_DELAY 0x2400 | 423 | #define BWI_PHYTBL_DELAY 0x2400 | |
424 | #define BWI_PHYTBL_RSSI 0x4000 | 424 | #define BWI_PHYTBL_RSSI 0x4000 | |
425 | #define BWI_PHYTBL_SIGMA_SQ 0x5000 | 425 | #define BWI_PHYTBL_SIGMA_SQ 0x5000 | |
426 | #define BWI_PHYTBL_WRSSI_REV1 0x5400 | 426 | #define BWI_PHYTBL_WRSSI_REV1 0x5400 | |
427 | #define BWI_PHYTBL_FREQ 0x5800 | 427 | #define BWI_PHYTBL_FREQ 0x5800 | |
428 | 428 | |||
429 | static const uint16_t bwi_phy_freq_11g_rev1[] = | 429 | static const uint16_t bwi_phy_freq_11g_rev1[] = | |
430 | { BWI_PHY_FREQ_11G_REV1 }; | 430 | { BWI_PHY_FREQ_11G_REV1 }; | |
431 | static const uint16_t bwi_phy_noise_11g_rev1[] = | 431 | static const uint16_t bwi_phy_noise_11g_rev1[] = | |
432 | { BWI_PHY_NOISE_11G_REV1 }; | 432 | { BWI_PHY_NOISE_11G_REV1 }; | |
433 | static const uint16_t bwi_phy_noise_11g[] = | 433 | static const uint16_t bwi_phy_noise_11g[] = | |
434 | { BWI_PHY_NOISE_11G }; | 434 | { BWI_PHY_NOISE_11G }; | |
435 | static const uint32_t bwi_phy_rotor_11g_rev1[] = | 435 | static const uint32_t bwi_phy_rotor_11g_rev1[] = | |
436 | { BWI_PHY_ROTOR_11G_REV1 }; | 436 | { BWI_PHY_ROTOR_11G_REV1 }; | |
437 | static const uint16_t bwi_phy_noise_scale_11g_rev2[] = | 437 | static const uint16_t bwi_phy_noise_scale_11g_rev2[] = | |
438 | { BWI_PHY_NOISE_SCALE_11G_REV2 }; | 438 | { BWI_PHY_NOISE_SCALE_11G_REV2 }; | |
439 | static const uint16_t bwi_phy_noise_scale_11g_rev7[] = | 439 | static const uint16_t bwi_phy_noise_scale_11g_rev7[] = | |
440 | { BWI_PHY_NOISE_SCALE_11G_REV7 }; | 440 | { BWI_PHY_NOISE_SCALE_11G_REV7 }; | |
441 | static const uint16_t bwi_phy_noise_scale_11g[] = | 441 | static const uint16_t bwi_phy_noise_scale_11g[] = | |
442 | { BWI_PHY_NOISE_SCALE_11G }; | 442 | { BWI_PHY_NOISE_SCALE_11G }; | |
443 | static const uint16_t bwi_phy_sigma_sq_11g_rev2[] = | 443 | static const uint16_t bwi_phy_sigma_sq_11g_rev2[] = | |
444 | { BWI_PHY_SIGMA_SQ_11G_REV2 }; | 444 | { BWI_PHY_SIGMA_SQ_11G_REV2 }; | |
445 | static const uint16_t bwi_phy_sigma_sq_11g_rev7[] = | 445 | static const uint16_t bwi_phy_sigma_sq_11g_rev7[] = | |
446 | { BWI_PHY_SIGMA_SQ_11G_REV7 }; | 446 | { BWI_PHY_SIGMA_SQ_11G_REV7 }; | |
447 | static const uint32_t bwi_phy_delay_11g_rev1[] = | 447 | static const uint32_t bwi_phy_delay_11g_rev1[] = | |
448 | { BWI_PHY_DELAY_11G_REV1 }; | 448 | { BWI_PHY_DELAY_11G_REV1 }; | |
449 | 449 | |||
450 | /* RF */ | 450 | /* RF */ | |
451 | #define RF_LO_WRITE(mac, lo) bwi_rf_lo_write((mac), (lo)) | 451 | #define RF_LO_WRITE(mac, lo) bwi_rf_lo_write((mac), (lo)) | |
452 | 452 | |||
453 | #define BWI_RF_2GHZ_CHAN(chan) \ | 453 | #define BWI_RF_2GHZ_CHAN(chan) \ | |
454 | (ieee80211_ieee2mhz((chan), IEEE80211_CHAN_2GHZ) - 2400) | 454 | (ieee80211_ieee2mhz((chan), IEEE80211_CHAN_2GHZ) - 2400) | |
455 | 455 | |||
456 | #define BWI_DEFAULT_IDLE_TSSI 52 | 456 | #define BWI_DEFAULT_IDLE_TSSI 52 | |
457 | 457 | |||
458 | struct rf_saveregs { | 458 | struct rf_saveregs { | |
459 | uint16_t phy_01; | 459 | uint16_t phy_01; | |
460 | uint16_t phy_03; | 460 | uint16_t phy_03; | |
461 | uint16_t phy_0a; | 461 | uint16_t phy_0a; | |
462 | uint16_t phy_15; | 462 | uint16_t phy_15; | |
463 | uint16_t phy_2a; | 463 | uint16_t phy_2a; | |
464 | uint16_t phy_30; | 464 | uint16_t phy_30; | |
465 | uint16_t phy_35; | 465 | uint16_t phy_35; | |
466 | uint16_t phy_60; | 466 | uint16_t phy_60; | |
467 | uint16_t phy_429; | 467 | uint16_t phy_429; | |
468 | uint16_t phy_802; | 468 | uint16_t phy_802; | |
469 | uint16_t phy_811; | 469 | uint16_t phy_811; | |
470 | uint16_t phy_812; | 470 | uint16_t phy_812; | |
471 | uint16_t phy_814; | 471 | uint16_t phy_814; | |
472 | uint16_t phy_815; | 472 | uint16_t phy_815; | |
473 | 473 | |||
474 | uint16_t rf_43; | 474 | uint16_t rf_43; | |
475 | uint16_t rf_52; | 475 | uint16_t rf_52; | |
476 | uint16_t rf_7a; | 476 | uint16_t rf_7a; | |
477 | }; | 477 | }; | |
478 | 478 | |||
479 | #define SAVE_RF_REG(mac, regs, n) (regs)->rf_##n = RF_READ((mac), 0x##n) | 479 | #define SAVE_RF_REG(mac, regs, n) (regs)->rf_##n = RF_READ((mac), 0x##n) | |
480 | #define RESTORE_RF_REG(mac, regs, n) RF_WRITE((mac), 0x##n, (regs)->rf_##n) | 480 | #define RESTORE_RF_REG(mac, regs, n) RF_WRITE((mac), 0x##n, (regs)->rf_##n) | |
481 | 481 | |||
482 | #define SAVE_PHY_REG(mac, regs, n) (regs)->phy_##n = PHY_READ((mac), 0x##n) | 482 | #define SAVE_PHY_REG(mac, regs, n) (regs)->phy_##n = PHY_READ((mac), 0x##n) | |
483 | #define RESTORE_PHY_REG(mac, regs, n) PHY_WRITE((mac), 0x##n, (regs)->phy_##n) | 483 | #define RESTORE_PHY_REG(mac, regs, n) PHY_WRITE((mac), 0x##n, (regs)->phy_##n) | |
484 | 484 | |||
485 | static const int8_t bwi_txpower_map_11b[BWI_TSSI_MAX] = | 485 | static const int8_t bwi_txpower_map_11b[BWI_TSSI_MAX] = | |
486 | { BWI_TXPOWER_MAP_11B }; | 486 | { BWI_TXPOWER_MAP_11B }; | |
487 | static const int8_t bwi_txpower_map_11g[BWI_TSSI_MAX] = | 487 | static const int8_t bwi_txpower_map_11g[BWI_TSSI_MAX] = | |
488 | { BWI_TXPOWER_MAP_11G }; | 488 | { BWI_TXPOWER_MAP_11G }; | |
489 | 489 | |||
490 | /* INTERFACE */ | 490 | /* INTERFACE */ | |
491 | 491 | |||
492 | struct bwi_myaddr_bssid { | 492 | struct bwi_myaddr_bssid { | |
493 | uint8_t myaddr[IEEE80211_ADDR_LEN]; | 493 | uint8_t myaddr[IEEE80211_ADDR_LEN]; | |
494 | uint8_t bssid[IEEE80211_ADDR_LEN]; | 494 | uint8_t bssid[IEEE80211_ADDR_LEN]; | |
495 | } __packed; | 495 | } __packed; | |
496 | 496 | |||
497 | /* [TRC: XXX What are these about?] */ | 497 | /* [TRC: XXX What are these about?] */ | |
498 | 498 | |||
499 | #define IEEE80211_DS_PLCP_SERVICE_LOCKED 0x04 | 499 | #define IEEE80211_DS_PLCP_SERVICE_LOCKED 0x04 | |
500 | #define IEEE80211_DS_PLCL_SERVICE_PBCC 0x08 | 500 | #define IEEE80211_DS_PLCL_SERVICE_PBCC 0x08 | |
501 | #define IEEE80211_DS_PLCP_SERVICE_LENEXT5 0x20 | 501 | #define IEEE80211_DS_PLCP_SERVICE_LENEXT5 0x20 | |
502 | #define IEEE80211_DS_PLCP_SERVICE_LENEXT6 0x40 | 502 | #define IEEE80211_DS_PLCP_SERVICE_LENEXT6 0x40 | |
503 | #define IEEE80211_DS_PLCP_SERVICE_LENEXT7 0x80 | 503 | #define IEEE80211_DS_PLCP_SERVICE_LENEXT7 0x80 | |
504 | 504 | |||
505 | static const struct { | 505 | static const struct { | |
506 | uint16_t did_min; | 506 | uint16_t did_min; | |
507 | uint16_t did_max; | 507 | uint16_t did_max; | |
508 | uint16_t bbp_id; | 508 | uint16_t bbp_id; | |
509 | } bwi_bbpid_map[] = { | 509 | } bwi_bbpid_map[] = { | |
510 | { 0x4301, 0x4301, 0x4301 }, | 510 | { 0x4301, 0x4301, 0x4301 }, | |
511 | { 0x4305, 0x4307, 0x4307 }, | 511 | { 0x4305, 0x4307, 0x4307 }, | |
512 | { 0x4403, 0x4403, 0x4402 }, | 512 | { 0x4403, 0x4403, 0x4402 }, | |
513 | { 0x4610, 0x4615, 0x4610 }, | 513 | { 0x4610, 0x4615, 0x4610 }, | |
514 | { 0x4710, 0x4715, 0x4710 }, | 514 | { 0x4710, 0x4715, 0x4710 }, | |
515 | { 0x4720, 0x4725, 0x4309 } | 515 | { 0x4720, 0x4725, 0x4309 } | |
516 | }; | 516 | }; | |
517 | 517 | |||
518 | static const struct { | 518 | static const struct { | |
519 | uint16_t bbp_id; | 519 | uint16_t bbp_id; | |
520 | int nregwin; | 520 | int nregwin; | |
521 | } bwi_regwin_count[] = { | 521 | } bwi_regwin_count[] = { | |
522 | { 0x4301, 5 }, | 522 | { 0x4301, 5 }, | |
523 | { 0x4306, 6 }, | 523 | { 0x4306, 6 }, | |
524 | { 0x4307, 5 }, | 524 | { 0x4307, 5 }, | |
525 | { 0x4310, 8 }, | 525 | { 0x4310, 8 }, | |
526 | { 0x4401, 3 }, | 526 | { 0x4401, 3 }, | |
527 | { 0x4402, 3 }, | 527 | { 0x4402, 3 }, | |
528 | { 0x4610, 9 }, | 528 | { 0x4610, 9 }, | |
529 | { 0x4704, 9 }, | 529 | { 0x4704, 9 }, | |
530 | { 0x4710, 9 }, | 530 | { 0x4710, 9 }, | |
531 | { 0x5365, 7 } | 531 | { 0x5365, 7 } | |
532 | }; | 532 | }; | |
533 | 533 | |||
534 | #define CLKSRC(src) \ | 534 | #define CLKSRC(src) \ | |
535 | [BWI_CLKSRC_ ## src] = { \ | 535 | [BWI_CLKSRC_ ## src] = { \ | |
536 | .freq_min = BWI_CLKSRC_ ##src## _FMIN, \ | 536 | .freq_min = BWI_CLKSRC_ ##src## _FMIN, \ | |
537 | .freq_max = BWI_CLKSRC_ ##src## _FMAX \ | 537 | .freq_max = BWI_CLKSRC_ ##src## _FMAX \ | |
538 | } | 538 | } | |
539 | 539 | |||
540 | static const struct { | 540 | static const struct { | |
541 | uint freq_min; | 541 | uint freq_min; | |
542 | uint freq_max; | 542 | uint freq_max; | |
543 | } bwi_clkfreq[BWI_CLKSRC_MAX] = { | 543 | } bwi_clkfreq[BWI_CLKSRC_MAX] = { | |
544 | CLKSRC(LP_OSC), | 544 | CLKSRC(LP_OSC), | |
545 | CLKSRC(CS_OSC), | 545 | CLKSRC(CS_OSC), | |
546 | CLKSRC(PCI) | 546 | CLKSRC(PCI) | |
547 | }; | 547 | }; | |
548 | 548 | |||
549 | #undef CLKSRC | 549 | #undef CLKSRC | |
550 | 550 | |||
551 | #define VENDOR_LED_ACT(vendor) \ | 551 | #define VENDOR_LED_ACT(vendor) \ | |
552 | { \ | 552 | { \ | |
553 | .vid = PCI_VENDOR_##vendor, \ | 553 | .vid = PCI_VENDOR_##vendor, \ | |
554 | .led_act = { BWI_VENDOR_LED_ACT_##vendor } \ | 554 | .led_act = { BWI_VENDOR_LED_ACT_##vendor } \ | |
555 | } | 555 | } | |
556 | 556 | |||
557 | static const struct { | 557 | static const struct { | |
558 | uint16_t vid; | 558 | uint16_t vid; | |
559 | uint8_t led_act[BWI_LED_MAX]; | 559 | uint8_t led_act[BWI_LED_MAX]; | |
560 | } bwi_vendor_led_act[] = { | 560 | } bwi_vendor_led_act[] = { | |
561 | VENDOR_LED_ACT(COMPAQ), | 561 | VENDOR_LED_ACT(COMPAQ), | |
562 | VENDOR_LED_ACT(LINKSYS) | 562 | VENDOR_LED_ACT(LINKSYS) | |
563 | }; | 563 | }; | |
564 | 564 | |||
565 | static const uint8_t bwi_default_led_act[BWI_LED_MAX] = | 565 | static const uint8_t bwi_default_led_act[BWI_LED_MAX] = | |
566 | { BWI_VENDOR_LED_ACT_DEFAULT }; | 566 | { BWI_VENDOR_LED_ACT_DEFAULT }; | |
567 | 567 | |||
568 | #undef VENDOR_LED_ACT | 568 | #undef VENDOR_LED_ACT | |
569 | 569 | |||
570 | static const struct { | 570 | static const struct { | |
571 | int on_dur; | 571 | int on_dur; | |
572 | int off_dur; | 572 | int off_dur; | |
573 | } bwi_led_duration[109] = { | 573 | } bwi_led_duration[109] = { | |
574 | [0] = { 400, 100 }, | 574 | [0] = { 400, 100 }, | |
575 | [2] = { 150, 75 }, | 575 | [2] = { 150, 75 }, | |
576 | [4] = { 90, 45 }, | 576 | [4] = { 90, 45 }, | |
577 | [11] = { 66, 34 }, | 577 | [11] = { 66, 34 }, | |
578 | [12] = { 53, 26 }, | 578 | [12] = { 53, 26 }, | |
579 | [18] = { 42, 21 }, | 579 | [18] = { 42, 21 }, | |
580 | [22] = { 35, 17 }, | 580 | [22] = { 35, 17 }, | |
581 | [24] = { 32, 16 }, | 581 | [24] = { 32, 16 }, | |
582 | [36] = { 21, 10 }, | 582 | [36] = { 21, 10 }, | |
583 | [48] = { 16, 8 }, | 583 | [48] = { 16, 8 }, | |
584 | [72] = { 11, 5 }, | 584 | [72] = { 11, 5 }, | |
585 | [96] = { 9, 4 }, | 585 | [96] = { 9, 4 }, | |
586 | [108] = { 7, 3 } | 586 | [108] = { 7, 3 } | |
587 | }; | 587 | }; | |
588 | 588 | |||
589 | /* [TRC: XXX Should this be zeroed?] */ | 589 | /* [TRC: XXX Should this be zeroed?] */ | |
590 | 590 | |||
591 | static const uint8_t bwi_zero_addr[IEEE80211_ADDR_LEN]; | 591 | static const uint8_t bwi_zero_addr[IEEE80211_ADDR_LEN]; | |
592 | 592 | |||
593 | /* [TRC: Derived from DragonFly's src/sys/netproto/802_11/_ieee80211.h */ | 593 | /* [TRC: Derived from DragonFly's src/sys/netproto/802_11/_ieee80211.h */ | |
594 | 594 | |||
595 | enum bwi_ieee80211_modtype { | 595 | enum bwi_ieee80211_modtype { | |
596 | IEEE80211_MODTYPE_DS = 0, /* DS/CCK modulation */ | 596 | IEEE80211_MODTYPE_DS = 0, /* DS/CCK modulation */ | |
597 | IEEE80211_MODTYPE_PBCC = 1, /* PBCC modulation */ | 597 | IEEE80211_MODTYPE_PBCC = 1, /* PBCC modulation */ | |
598 | IEEE80211_MODTYPE_OFDM = 2 /* OFDM modulation */ | 598 | IEEE80211_MODTYPE_OFDM = 2 /* OFDM modulation */ | |
599 | }; | 599 | }; | |
600 | #define IEEE80211_MODTYPE_CCK IEEE80211_MODTYPE_DS | 600 | #define IEEE80211_MODTYPE_CCK IEEE80211_MODTYPE_DS | |
601 | 601 | |||
602 | /* | 602 | /* | |
603 | * Setup sysctl(3) MIB, hw.bwi.* and hw.bwiN.* | 603 | * Setup sysctl(3) MIB, hw.bwi.* and hw.bwiN.* | |
604 | */ | 604 | */ | |
605 | 605 | |||
606 | #ifdef BWI_DEBUG | 606 | #ifdef BWI_DEBUG | |
607 | SYSCTL_SETUP(sysctl_bwi, "sysctl bwi(4) subtree setup") | 607 | SYSCTL_SETUP(sysctl_bwi, "sysctl bwi(4) subtree setup") | |
608 | { | 608 | { | |
609 | int rc; | 609 | int rc; | |
610 | const struct sysctlnode *rnode; | 610 | const struct sysctlnode *rnode; | |
611 | const struct sysctlnode *cnode; | 611 | const struct sysctlnode *cnode; | |
612 | 612 | |||
613 | if ((rc = sysctl_createv(clog, 0, NULL, &rnode, | 613 | if ((rc = sysctl_createv(clog, 0, NULL, &rnode, | |
614 | CTLFLAG_PERMANENT, CTLTYPE_NODE, "bwi", | 614 | CTLFLAG_PERMANENT, CTLTYPE_NODE, "bwi", | |
615 | SYSCTL_DESCR("bwi global controls"), | 615 | SYSCTL_DESCR("bwi global controls"), | |
616 | NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL)) != 0) | 616 | NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL)) != 0) | |
617 | goto err; | 617 | goto err; | |
618 | 618 | |||
619 | if ((rc = sysctl_createv(clog, 0, &rnode, &cnode, | 619 | if ((rc = sysctl_createv(clog, 0, &rnode, &cnode, | |
620 | CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT, | 620 | CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT, | |
621 | "debug", SYSCTL_DESCR("default debug flags"), | 621 | "debug", SYSCTL_DESCR("default debug flags"), | |
622 | NULL, 0, &bwi_debug, 0, CTL_CREATE, CTL_EOL)) != 0) | 622 | NULL, 0, &bwi_debug, 0, CTL_CREATE, CTL_EOL)) != 0) | |
623 | goto err; | 623 | goto err; | |
624 | 624 | |||
625 | return; | 625 | return; | |
626 | 626 | |||
627 | err: | 627 | err: | |
628 | aprint_error("%s: sysctl_createv failed (rc = %d)\n", __func__, rc); | 628 | aprint_error("%s: sysctl_createv failed (rc = %d)\n", __func__, rc); | |
629 | } | 629 | } | |
630 | #endif /* BWI_DEBUG */ | 630 | #endif /* BWI_DEBUG */ | |
631 | 631 | |||
632 | static void | 632 | static void | |
633 | bwi_sysctlattach(struct bwi_softc *sc) | 633 | bwi_sysctlattach(struct bwi_softc *sc) | |
634 | { | 634 | { | |
635 | int rc; | 635 | int rc; | |
636 | const struct sysctlnode *rnode; | 636 | const struct sysctlnode *rnode; | |
637 | const struct sysctlnode *cnode; | 637 | const struct sysctlnode *cnode; | |
638 | 638 | |||
639 | struct sysctllog **clog = &sc->sc_sysctllog; | 639 | struct sysctllog **clog = &sc->sc_sysctllog; | |
640 | 640 | |||
641 | if ((rc = sysctl_createv(clog, 0, NULL, &rnode, | 641 | if ((rc = sysctl_createv(clog, 0, NULL, &rnode, | |
642 | CTLFLAG_PERMANENT, CTLTYPE_NODE, device_xname(sc->sc_dev), | 642 | CTLFLAG_PERMANENT, CTLTYPE_NODE, device_xname(sc->sc_dev), | |
643 | SYSCTL_DESCR("bwi controls and statistics"), | 643 | SYSCTL_DESCR("bwi controls and statistics"), | |
644 | NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL)) != 0) | 644 | NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL)) != 0) | |
645 | goto err; | 645 | goto err; | |
646 | 646 | |||
647 | if ((rc = sysctl_createv(clog, 0, &rnode, &cnode, | 647 | if ((rc = sysctl_createv(clog, 0, &rnode, &cnode, | |
648 | CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT, | 648 | CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT, | |
649 | "fw_version", SYSCTL_DESCR("firmware version"), | 649 | "fw_version", SYSCTL_DESCR("firmware version"), | |
650 | NULL, 0, &sc->sc_fw_version, 0, CTL_CREATE, CTL_EOL)) != 0) | 650 | NULL, 0, &sc->sc_fw_version, 0, CTL_CREATE, CTL_EOL)) != 0) | |
651 | goto err; | 651 | goto err; | |
652 | 652 | |||
653 | if ((rc = sysctl_createv(clog, 0, &rnode, &cnode, | 653 | if ((rc = sysctl_createv(clog, 0, &rnode, &cnode, | |
654 | CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT, | 654 | CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT, | |
655 | "dwell_time", SYSCTL_DESCR("channel dwell time during scan (msec)"), | 655 | "dwell_time", SYSCTL_DESCR("channel dwell time during scan (msec)"), | |
656 | NULL, 0, &sc->sc_dwell_time, 0, CTL_CREATE, CTL_EOL)) != 0) | 656 | NULL, 0, &sc->sc_dwell_time, 0, CTL_CREATE, CTL_EOL)) != 0) | |
657 | goto err; | 657 | goto err; | |
658 | 658 | |||
659 | if ((rc = sysctl_createv(clog, 0, &rnode, &cnode, | 659 | if ((rc = sysctl_createv(clog, 0, &rnode, &cnode, | |
660 | CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT, | 660 | CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT, | |
661 | "led_idle", SYSCTL_DESCR("# ticks before LED enters idle state"), | 661 | "led_idle", SYSCTL_DESCR("# ticks before LED enters idle state"), | |
662 | NULL, 0, &sc->sc_led_idle, 0, CTL_CREATE, CTL_EOL)) != 0) | 662 | NULL, 0, &sc->sc_led_idle, 0, CTL_CREATE, CTL_EOL)) != 0) | |
663 | goto err; | 663 | goto err; | |
664 | 664 | |||
665 | if ((rc = sysctl_createv(clog, 0, &rnode, &cnode, | 665 | if ((rc = sysctl_createv(clog, 0, &rnode, &cnode, | |
666 | CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT, | 666 | CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT, | |
667 | "led_blink", SYSCTL_DESCR("allow LED to blink"), | 667 | "led_blink", SYSCTL_DESCR("allow LED to blink"), | |
668 | NULL, 0, &sc->sc_led_blink, 0, CTL_CREATE, CTL_EOL)) != 0) | 668 | NULL, 0, &sc->sc_led_blink, 0, CTL_CREATE, CTL_EOL)) != 0) | |
669 | goto err; | 669 | goto err; | |
670 | 670 | |||
671 | if ((rc = sysctl_createv(clog, 0, &rnode, &cnode, | 671 | if ((rc = sysctl_createv(clog, 0, &rnode, &cnode, | |
672 | CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT, | 672 | CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT, | |
673 | "txpwr_calib", SYSCTL_DESCR("enable software TX power calibration"), | 673 | "txpwr_calib", SYSCTL_DESCR("enable software TX power calibration"), | |
674 | NULL, 0, &sc->sc_txpwr_calib, 0, CTL_CREATE, CTL_EOL)) != 0) | 674 | NULL, 0, &sc->sc_txpwr_calib, 0, CTL_CREATE, CTL_EOL)) != 0) | |
675 | goto err; | 675 | goto err; | |
676 | 676 | |||
677 | #ifdef BWI_DEBUG | 677 | #ifdef BWI_DEBUG | |
678 | if ((rc = sysctl_createv(clog, 0, &rnode, &cnode, | 678 | if ((rc = sysctl_createv(clog, 0, &rnode, &cnode, | |
679 | CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT, | 679 | CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT, | |
680 | "debug", SYSCTL_DESCR("debug flags"), | 680 | "debug", SYSCTL_DESCR("debug flags"), | |
681 | NULL, 0, &sc->sc_debug, 0, CTL_CREATE, CTL_EOL)) != 0) | 681 | NULL, 0, &sc->sc_debug, 0, CTL_CREATE, CTL_EOL)) != 0) | |
682 | goto err; | 682 | goto err; | |
683 | #endif | 683 | #endif | |
684 | 684 | |||
685 | return; | 685 | return; | |
686 | 686 | |||
687 | err: | 687 | err: | |
688 | aprint_error("%s: sysctl_createv failed (rc = %d)\n", __func__, rc); | 688 | aprint_error("%s: sysctl_createv failed (rc = %d)\n", __func__, rc); | |
689 | } | 689 | } | |
690 | 690 | |||
691 | /* CODE */ | 691 | /* CODE */ | |
692 | 692 | |||
693 | int | 693 | int | |
694 | bwi_intr(void *arg) | 694 | bwi_intr(void *arg) | |
695 | { | 695 | { | |
696 | struct bwi_softc *sc = arg; | 696 | struct bwi_softc *sc = arg; | |
697 | struct ifnet *ifp = &sc->sc_if; | 697 | struct ifnet *ifp = &sc->sc_if; | |
698 | 698 | |||
699 | if (!device_is_active(sc->sc_dev) || | 699 | if (!device_is_active(sc->sc_dev) || | |
700 | (ifp->if_flags & IFF_RUNNING) == 0) | 700 | (ifp->if_flags & IFF_RUNNING) == 0) | |
701 | return (0); | 701 | return (0); | |
702 | 702 | |||
703 | /* Disable all interrupts */ | 703 | /* Disable all interrupts */ | |
704 | bwi_disable_intrs(sc, BWI_ALL_INTRS); | 704 | bwi_disable_intrs(sc, BWI_ALL_INTRS); | |
705 | 705 | |||
706 | softint_schedule(sc->sc_soft_ih); | 706 | softint_schedule(sc->sc_soft_ih); | |
707 | return (1); | 707 | return (1); | |
708 | } | 708 | } | |
709 | 709 | |||
710 | static void | 710 | static void | |
711 | bwi_softintr(void *arg) | 711 | bwi_softintr(void *arg) | |
712 | { | 712 | { | |
713 | struct bwi_softc *sc = arg; | 713 | struct bwi_softc *sc = arg; | |
714 | struct bwi_mac *mac; | 714 | struct bwi_mac *mac; | |
715 | struct ifnet *ifp = &sc->sc_if; | 715 | struct ifnet *ifp = &sc->sc_if; | |
716 | uint32_t intr_status; | 716 | uint32_t intr_status; | |
717 | uint32_t txrx_intr_status[BWI_TXRX_NRING]; | 717 | uint32_t txrx_intr_status[BWI_TXRX_NRING]; | |
718 | int i, s, txrx_error, tx = 0, rx_data = -1; | 718 | int i, s, txrx_error, tx = 0, rx_data = -1; | |
719 | 719 | |||
720 | if (!device_is_active(sc->sc_dev) || | 720 | if (!device_is_active(sc->sc_dev) || | |
721 | (ifp->if_flags & IFF_RUNNING) == 0) | 721 | (ifp->if_flags & IFF_RUNNING) == 0) | |
722 | return; | 722 | return; | |
723 | 723 | |||
724 | for (;;) { | 724 | for (;;) { | |
725 | /* | 725 | /* | |
726 | * Get interrupt status | 726 | * Get interrupt status | |
727 | */ | 727 | */ | |
728 | intr_status = CSR_READ_4(sc, BWI_MAC_INTR_STATUS); | 728 | intr_status = CSR_READ_4(sc, BWI_MAC_INTR_STATUS); | |
729 | if (intr_status == 0xffffffff) /* Not for us */ | 729 | if (intr_status == 0xffffffff) /* Not for us */ | |
730 | goto out; | 730 | goto out; | |
731 | 731 | |||
732 | intr_status &= CSR_READ_4(sc, BWI_MAC_INTR_MASK); | 732 | intr_status &= CSR_READ_4(sc, BWI_MAC_INTR_MASK); | |
733 | if (intr_status == 0) /* Nothing is interesting */ | 733 | if (intr_status == 0) /* Nothing is interesting */ | |
734 | goto out; | 734 | goto out; | |
735 | 735 | |||
736 | DPRINTF(sc, BWI_DBG_INTR, "intr status 0x%08x\n", intr_status); | 736 | DPRINTF(sc, BWI_DBG_INTR, "intr status 0x%08x\n", intr_status); | |
737 | 737 | |||
738 | KASSERT(sc->sc_cur_regwin->rw_type == BWI_REGWIN_T_MAC); | 738 | KASSERT(sc->sc_cur_regwin->rw_type == BWI_REGWIN_T_MAC); | |
739 | mac = (struct bwi_mac *)sc->sc_cur_regwin; | 739 | mac = (struct bwi_mac *)sc->sc_cur_regwin; | |
740 | 740 | |||
741 | txrx_error = 0; | 741 | txrx_error = 0; | |
742 | 742 | |||
743 | for (i = 0; i < BWI_TXRX_NRING; ++i) { | 743 | for (i = 0; i < BWI_TXRX_NRING; ++i) { | |
744 | uint32_t mask; | 744 | uint32_t mask; | |
745 | 745 | |||
746 | if (BWI_TXRX_IS_RX(i)) | 746 | if (BWI_TXRX_IS_RX(i)) | |
747 | mask = BWI_TXRX_RX_INTRS; | 747 | mask = BWI_TXRX_RX_INTRS; | |
748 | else | 748 | else | |
749 | mask = BWI_TXRX_TX_INTRS; | 749 | mask = BWI_TXRX_TX_INTRS; | |
750 | 750 | |||
751 | txrx_intr_status[i] = | 751 | txrx_intr_status[i] = | |
752 | CSR_READ_4(sc, BWI_TXRX_INTR_STATUS(i)) & mask; | 752 | CSR_READ_4(sc, BWI_TXRX_INTR_STATUS(i)) & mask; | |
753 | 753 | |||
754 | if (txrx_intr_status[i] & BWI_TXRX_INTR_ERROR) { | 754 | if (txrx_intr_status[i] & BWI_TXRX_INTR_ERROR) { | |
755 | aprint_error_dev(sc->sc_dev, | 755 | aprint_error_dev(sc->sc_dev, | |
756 | "intr fatal TX/RX (%d) error 0x%08x\n", | 756 | "intr fatal TX/RX (%d) error 0x%08x\n", | |
757 | i, txrx_intr_status[i]); | 757 | i, txrx_intr_status[i]); | |
758 | txrx_error = 1; | 758 | txrx_error = 1; | |
759 | } | 759 | } | |
760 | } | 760 | } | |
761 | 761 | |||
762 | /* | 762 | /* | |
763 | * Acknowledge interrupt | 763 | * Acknowledge interrupt | |
764 | */ | 764 | */ | |
765 | CSR_WRITE_4(sc, BWI_MAC_INTR_STATUS, intr_status); | 765 | CSR_WRITE_4(sc, BWI_MAC_INTR_STATUS, intr_status); | |
766 | 766 | |||
767 | for (i = 0; i < BWI_TXRX_NRING; ++i) | 767 | for (i = 0; i < BWI_TXRX_NRING; ++i) | |
768 | CSR_WRITE_4(sc, BWI_TXRX_INTR_STATUS(i), | 768 | CSR_WRITE_4(sc, BWI_TXRX_INTR_STATUS(i), | |
769 | txrx_intr_status[i]); | 769 | txrx_intr_status[i]); | |
770 | 770 | |||
771 | if (intr_status & BWI_INTR_PHY_TXERR) { | 771 | if (intr_status & BWI_INTR_PHY_TXERR) { | |
772 | if (mac->mac_flags & BWI_MAC_F_PHYE_RESET) { | 772 | if (mac->mac_flags & BWI_MAC_F_PHYE_RESET) { | |
773 | aprint_error_dev(sc->sc_dev, | 773 | aprint_error_dev(sc->sc_dev, | |
774 | "intr PHY TX error\n"); | 774 | "intr PHY TX error\n"); | |
775 | /* XXX to netisr0? */ | 775 | /* XXX to netisr0? */ | |
776 | s = splnet(); | 776 | s = splnet(); | |
777 | bwi_init_statechg(sc, 0); | 777 | bwi_init_statechg(sc, 0); | |
778 | splx(s); | 778 | splx(s); | |
779 | goto out; | 779 | goto out; | |
780 | } | 780 | } | |
781 | } | 781 | } | |
782 | 782 | |||
783 | if (txrx_error) { | 783 | if (txrx_error) { | |
784 | /* TODO: reset device */ | 784 | /* TODO: reset device */ | |
785 | } | 785 | } | |
786 | 786 | |||
787 | if (intr_status & BWI_INTR_TBTT) | 787 | if (intr_status & BWI_INTR_TBTT) | |
788 | bwi_mac_config_ps(mac); | 788 | bwi_mac_config_ps(mac); | |
789 | 789 | |||
790 | if (intr_status & BWI_INTR_EO_ATIM) | 790 | if (intr_status & BWI_INTR_EO_ATIM) | |
791 | aprint_normal_dev(sc->sc_dev, "EO_ATIM\n"); | 791 | aprint_normal_dev(sc->sc_dev, "EO_ATIM\n"); | |
792 | 792 | |||
793 | if (intr_status & BWI_INTR_PMQ) { | 793 | if (intr_status & BWI_INTR_PMQ) { | |
794 | for (;;) { | 794 | for (;;) { | |
795 | if ((CSR_READ_4(sc, BWI_MAC_PS_STATUS) & 0x8) | 795 | if ((CSR_READ_4(sc, BWI_MAC_PS_STATUS) & 0x8) | |
796 | == 0) | 796 | == 0) | |
797 | break; | 797 | break; | |
798 | } | 798 | } | |
799 | CSR_WRITE_2(sc, BWI_MAC_PS_STATUS, 0x2); | 799 | CSR_WRITE_2(sc, BWI_MAC_PS_STATUS, 0x2); | |
800 | } | 800 | } | |
801 | 801 | |||
802 | if (intr_status & BWI_INTR_NOISE) | 802 | if (intr_status & BWI_INTR_NOISE) | |
803 | aprint_normal_dev(sc->sc_dev, "intr noise\n"); | 803 | aprint_normal_dev(sc->sc_dev, "intr noise\n"); | |
804 | 804 | |||
805 | if (txrx_intr_status[0] & BWI_TXRX_INTR_RX) | 805 | if (txrx_intr_status[0] & BWI_TXRX_INTR_RX) | |
806 | rx_data = (sc->sc_rxeof)(sc); | 806 | rx_data = (sc->sc_rxeof)(sc); | |
807 | 807 | |||
808 | if (txrx_intr_status[3] & BWI_TXRX_INTR_RX) { | 808 | if (txrx_intr_status[3] & BWI_TXRX_INTR_RX) { | |
809 | (sc->sc_txeof_status)(sc); | 809 | (sc->sc_txeof_status)(sc); | |
810 | tx = 1; | 810 | tx = 1; | |
811 | } | 811 | } | |
812 | 812 | |||
813 | if (intr_status & BWI_INTR_TX_DONE) { | 813 | if (intr_status & BWI_INTR_TX_DONE) { | |
814 | bwi_txeof(sc); | 814 | bwi_txeof(sc); | |
815 | tx = 1; | 815 | tx = 1; | |
816 | } | 816 | } | |
817 | 817 | |||
818 | if (sc->sc_blink_led != NULL && sc->sc_led_blink) { | 818 | if (sc->sc_blink_led != NULL && sc->sc_led_blink) { | |
819 | int evt = BWI_LED_EVENT_NONE; | 819 | int evt = BWI_LED_EVENT_NONE; | |
820 | 820 | |||
821 | if (tx && rx_data > 0) { | 821 | if (tx && rx_data > 0) { | |
822 | if (sc->sc_rx_rate > sc->sc_tx_rate) | 822 | if (sc->sc_rx_rate > sc->sc_tx_rate) | |
823 | evt = BWI_LED_EVENT_RX; | 823 | evt = BWI_LED_EVENT_RX; | |
824 | else | 824 | else | |
825 | evt = BWI_LED_EVENT_TX; | 825 | evt = BWI_LED_EVENT_TX; | |
826 | } else if (tx) { | 826 | } else if (tx) { | |
827 | evt = BWI_LED_EVENT_TX; | 827 | evt = BWI_LED_EVENT_TX; | |
828 | } else if (rx_data > 0) { | 828 | } else if (rx_data > 0) { | |
829 | evt = BWI_LED_EVENT_RX; | 829 | evt = BWI_LED_EVENT_RX; | |
830 | } else if (rx_data == 0) { | 830 | } else if (rx_data == 0) { | |
831 | evt = BWI_LED_EVENT_POLL; | 831 | evt = BWI_LED_EVENT_POLL; | |
832 | } | 832 | } | |
833 | 833 | |||
834 | if (evt != BWI_LED_EVENT_NONE) | 834 | if (evt != BWI_LED_EVENT_NONE) | |
835 | bwi_led_event(sc, evt); | 835 | bwi_led_event(sc, evt); | |
836 | } | 836 | } | |
837 | } | 837 | } | |
838 | 838 | |||
839 | out: | 839 | out: | |
840 | /* Re-enable interrupts */ | 840 | /* Re-enable interrupts */ | |
841 | bwi_enable_intrs(sc, BWI_INIT_INTRS); | 841 | bwi_enable_intrs(sc, BWI_INIT_INTRS); | |
842 | } | 842 | } | |
843 | 843 | |||
844 | int | 844 | int | |
845 | bwi_attach(struct bwi_softc *sc) | 845 | bwi_attach(struct bwi_softc *sc) | |
846 | { | 846 | { | |
847 | struct ieee80211com *ic = &sc->sc_ic; | 847 | struct ieee80211com *ic = &sc->sc_ic; | |
848 | struct ifnet *ifp = &sc->sc_if; | 848 | struct ifnet *ifp = &sc->sc_if; | |
849 | struct bwi_mac *mac; | 849 | struct bwi_mac *mac; | |
850 | struct bwi_phy *phy; | 850 | struct bwi_phy *phy; | |
851 | int s, i, error; | 851 | int s, i, error; | |
852 | 852 | |||
853 | /* [TRC: XXX Is this necessary?] */ | 853 | /* [TRC: XXX Is this necessary?] */ | |
854 | s = splnet(); | 854 | s = splnet(); | |
855 | 855 | |||
856 | sc->sc_soft_ih = softint_establish(SOFTINT_NET, bwi_softintr, sc); | 856 | sc->sc_soft_ih = softint_establish(SOFTINT_NET, bwi_softintr, sc); | |
857 | if (sc->sc_soft_ih == NULL) { | 857 | if (sc->sc_soft_ih == NULL) { | |
858 | error = ENXIO; | 858 | error = ENXIO; | |
859 | goto fail; | 859 | goto fail; | |
860 | } | 860 | } | |
861 | 861 | |||
862 | /* | 862 | /* | |
863 | * Initialize sysctl variables | 863 | * Initialize sysctl variables | |
864 | */ | 864 | */ | |
865 | sc->sc_fw_version = BWI_FW_VERSION3; | 865 | sc->sc_fw_version = BWI_FW_VERSION3; | |
866 | sc->sc_dwell_time = 200; | 866 | sc->sc_dwell_time = 200; | |
867 | sc->sc_led_idle = (2350 * hz) / 1000; | 867 | sc->sc_led_idle = (2350 * hz) / 1000; | |
868 | sc->sc_led_blink = 1; | 868 | sc->sc_led_blink = 1; | |
869 | sc->sc_txpwr_calib = 1; | 869 | sc->sc_txpwr_calib = 1; | |
870 | #ifdef BWI_DEBUG | 870 | #ifdef BWI_DEBUG | |
871 | sc->sc_debug = bwi_debug; | 871 | sc->sc_debug = bwi_debug; | |
872 | #endif | 872 | #endif | |
873 | 873 | |||
874 | DPRINTF(sc, BWI_DBG_ATTACH, "%s\n", __func__); | 874 | DPRINTF(sc, BWI_DBG_ATTACH, "%s\n", __func__); | |
875 | 875 | |||
876 | /* [TRC: XXX amrr] */ | 876 | /* [TRC: XXX amrr] */ | |
877 | /* AMRR rate control */ | 877 | /* AMRR rate control */ | |
878 | sc->sc_amrr.amrr_min_success_threshold = 1; | 878 | sc->sc_amrr.amrr_min_success_threshold = 1; | |
879 | sc->sc_amrr.amrr_max_success_threshold = 15; | 879 | sc->sc_amrr.amrr_max_success_threshold = 15; | |
880 | callout_init(&sc->sc_amrr_ch, 0); | 880 | callout_init(&sc->sc_amrr_ch, 0); | |
881 | callout_setfunc(&sc->sc_amrr_ch, bwi_amrr_timeout, sc); | 881 | callout_setfunc(&sc->sc_amrr_ch, bwi_amrr_timeout, sc); | |
882 | 882 | |||
883 | callout_init(&sc->sc_scan_ch, 0); | 883 | callout_init(&sc->sc_scan_ch, 0); | |
884 | callout_setfunc(&sc->sc_scan_ch, bwi_next_scan, sc); | 884 | callout_setfunc(&sc->sc_scan_ch, bwi_next_scan, sc); | |
885 | callout_init(&sc->sc_calib_ch, 0); | 885 | callout_init(&sc->sc_calib_ch, 0); | |
886 | callout_setfunc(&sc->sc_calib_ch, bwi_calibrate, sc); | 886 | callout_setfunc(&sc->sc_calib_ch, bwi_calibrate, sc); | |
887 | 887 | |||
888 | bwi_sysctlattach(sc); | 888 | bwi_sysctlattach(sc); | |
889 | 889 | |||
890 | bwi_power_on(sc, 1); | 890 | bwi_power_on(sc, 1); | |
891 | 891 | |||
892 | error = bwi_bbp_attach(sc); | 892 | error = bwi_bbp_attach(sc); | |
893 | if (error) | 893 | if (error) | |
894 | goto fail; | 894 | goto fail; | |
895 | 895 | |||
896 | error = bwi_bbp_power_on(sc, BWI_CLOCK_MODE_FAST); | 896 | error = bwi_bbp_power_on(sc, BWI_CLOCK_MODE_FAST); | |
897 | if (error) | 897 | if (error) | |
898 | goto fail; | 898 | goto fail; | |
899 | 899 | |||
900 | if (BWI_REGWIN_EXIST(&sc->sc_com_regwin)) { | 900 | if (BWI_REGWIN_EXIST(&sc->sc_com_regwin)) { | |
901 | error = bwi_set_clock_delay(sc); | 901 | error = bwi_set_clock_delay(sc); | |
902 | if (error) | 902 | if (error) | |
903 | goto fail; | 903 | goto fail; | |
904 | 904 | |||
905 | error = bwi_set_clock_mode(sc, BWI_CLOCK_MODE_FAST); | 905 | error = bwi_set_clock_mode(sc, BWI_CLOCK_MODE_FAST); | |
906 | if (error) | 906 | if (error) | |
907 | goto fail; | 907 | goto fail; | |
908 | 908 | |||
909 | error = bwi_get_pwron_delay(sc); | 909 | error = bwi_get_pwron_delay(sc); | |
910 | if (error) | 910 | if (error) | |
911 | goto fail; | 911 | goto fail; | |
912 | } | 912 | } | |
913 | 913 | |||
914 | error = bwi_bus_attach(sc); | 914 | error = bwi_bus_attach(sc); | |
915 | if (error) | 915 | if (error) | |
916 | goto fail; | 916 | goto fail; | |
917 | 917 | |||
918 | bwi_get_card_flags(sc); | 918 | bwi_get_card_flags(sc); | |
919 | 919 | |||
920 | bwi_led_attach(sc); | 920 | bwi_led_attach(sc); | |
921 | 921 | |||
922 | for (i = 0; i < sc->sc_nmac; ++i) { | 922 | for (i = 0; i < sc->sc_nmac; ++i) { | |
923 | struct bwi_regwin *old; | 923 | struct bwi_regwin *old; | |
924 | 924 | |||
925 | mac = &sc->sc_mac[i]; | 925 | mac = &sc->sc_mac[i]; | |
926 | error = bwi_regwin_switch(sc, &mac->mac_regwin, &old); | 926 | error = bwi_regwin_switch(sc, &mac->mac_regwin, &old); | |
927 | if (error) | 927 | if (error) | |
928 | goto fail; | 928 | goto fail; | |
929 | 929 | |||
930 | error = bwi_mac_lateattach(mac); | 930 | error = bwi_mac_lateattach(mac); | |
931 | if (error) | 931 | if (error) | |
932 | goto fail; | 932 | goto fail; | |
933 | 933 | |||
934 | error = bwi_regwin_switch(sc, old, NULL); | 934 | error = bwi_regwin_switch(sc, old, NULL); | |
935 | if (error) | 935 | if (error) | |
936 | goto fail; | 936 | goto fail; | |
937 | } | 937 | } | |
938 | 938 | |||
939 | /* | 939 | /* | |
940 | * XXX First MAC is known to exist | 940 | * XXX First MAC is known to exist | |
941 | * TODO2 | 941 | * TODO2 | |
942 | */ | 942 | */ | |
943 | mac = &sc->sc_mac[0]; | 943 | mac = &sc->sc_mac[0]; | |
944 | phy = &mac->mac_phy; | 944 | phy = &mac->mac_phy; | |
945 | 945 | |||
946 | bwi_bbp_power_off(sc); | 946 | bwi_bbp_power_off(sc); | |
947 | 947 | |||
948 | error = bwi_dma_alloc(sc); | 948 | error = bwi_dma_alloc(sc); | |
949 | if (error) | 949 | if (error) | |
950 | goto fail; | 950 | goto fail; | |
951 | 951 | |||
952 | /* setup interface */ | 952 | /* setup interface */ | |
953 | ifp->if_softc = sc; | 953 | ifp->if_softc = sc; | |
954 | ifp->if_init = bwi_init; | 954 | ifp->if_init = bwi_init; | |
955 | ifp->if_ioctl = bwi_ioctl; | 955 | ifp->if_ioctl = bwi_ioctl; | |
956 | ifp->if_start = bwi_start; | 956 | ifp->if_start = bwi_start; | |
957 | ifp->if_watchdog = bwi_watchdog; | 957 | ifp->if_watchdog = bwi_watchdog; | |
958 | ifp->if_stop = bwi_stop; | 958 | ifp->if_stop = bwi_stop; | |
959 | ifp->if_flags = IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST; | 959 | ifp->if_flags = IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST; | |
960 | memcpy(ifp->if_xname, device_xname(sc->sc_dev), IFNAMSIZ); | 960 | memcpy(ifp->if_xname, device_xname(sc->sc_dev), IFNAMSIZ); | |
961 | IFQ_SET_READY(&ifp->if_snd); | 961 | IFQ_SET_READY(&ifp->if_snd); | |
962 | 962 | |||
963 | /* Get locale */ | 963 | /* Get locale */ | |
964 | sc->sc_locale = __SHIFTOUT(bwi_read_sprom(sc, BWI_SPROM_CARD_INFO), | 964 | sc->sc_locale = __SHIFTOUT(bwi_read_sprom(sc, BWI_SPROM_CARD_INFO), | |
965 | BWI_SPROM_CARD_INFO_LOCALE); | 965 | BWI_SPROM_CARD_INFO_LOCALE); | |
966 | DPRINTF(sc, BWI_DBG_ATTACH, "locale: %d\n", sc->sc_locale); | 966 | DPRINTF(sc, BWI_DBG_ATTACH, "locale: %d\n", sc->sc_locale); | |
967 | 967 | |||
968 | /* | 968 | /* | |
969 | * Setup ratesets, phytype, channels and get MAC address | 969 | * Setup ratesets, phytype, channels and get MAC address | |
970 | */ | 970 | */ | |
971 | if (phy->phy_mode == IEEE80211_MODE_11B || | 971 | if (phy->phy_mode == IEEE80211_MODE_11B || | |
972 | phy->phy_mode == IEEE80211_MODE_11G) { | 972 | phy->phy_mode == IEEE80211_MODE_11G) { | |
973 | uint16_t chan_flags; | 973 | uint16_t chan_flags; | |
974 | 974 | |||
975 | ic->ic_sup_rates[IEEE80211_MODE_11B] = | 975 | ic->ic_sup_rates[IEEE80211_MODE_11B] = | |
976 | ieee80211_std_rateset_11b; | 976 | ieee80211_std_rateset_11b; | |
977 | 977 | |||
978 | if (phy->phy_mode == IEEE80211_MODE_11B) { | 978 | if (phy->phy_mode == IEEE80211_MODE_11B) { | |
979 | chan_flags = IEEE80211_CHAN_B; | 979 | chan_flags = IEEE80211_CHAN_B; | |
980 | ic->ic_phytype = IEEE80211_T_DS; | 980 | ic->ic_phytype = IEEE80211_T_DS; | |
981 | } else { | 981 | } else { | |
982 | chan_flags = IEEE80211_CHAN_CCK | | 982 | chan_flags = IEEE80211_CHAN_CCK | | |
983 | IEEE80211_CHAN_OFDM | | 983 | IEEE80211_CHAN_OFDM | | |
984 | IEEE80211_CHAN_DYN | | 984 | IEEE80211_CHAN_DYN | | |
985 | IEEE80211_CHAN_2GHZ; | 985 | IEEE80211_CHAN_2GHZ; | |
986 | ic->ic_phytype = IEEE80211_T_OFDM; | 986 | ic->ic_phytype = IEEE80211_T_OFDM; | |
987 | ic->ic_sup_rates[IEEE80211_MODE_11G] = | 987 | ic->ic_sup_rates[IEEE80211_MODE_11G] = | |
988 | ieee80211_std_rateset_11g; | 988 | ieee80211_std_rateset_11g; | |
989 | } | 989 | } | |
990 | 990 | |||
991 | /* XXX depend on locale */ | 991 | /* XXX depend on locale */ | |
992 | for (i = 1; i <= 14; ++i) { | 992 | for (i = 1; i <= 14; ++i) { | |
993 | ic->ic_channels[i].ic_freq = | 993 | ic->ic_channels[i].ic_freq = | |
994 | ieee80211_ieee2mhz(i, IEEE80211_CHAN_2GHZ); | 994 | ieee80211_ieee2mhz(i, IEEE80211_CHAN_2GHZ); | |
995 | ic->ic_channels[i].ic_flags = chan_flags; | 995 | ic->ic_channels[i].ic_flags = chan_flags; | |
996 | } | 996 | } | |
997 | 997 | |||
998 | bwi_get_eaddr(sc, BWI_SPROM_11BG_EADDR, ic->ic_myaddr); | 998 | bwi_get_eaddr(sc, BWI_SPROM_11BG_EADDR, ic->ic_myaddr); | |
999 | if (IEEE80211_IS_MULTICAST(ic->ic_myaddr)) { | 999 | if (IEEE80211_IS_MULTICAST(ic->ic_myaddr)) { | |
1000 | bwi_get_eaddr(sc, BWI_SPROM_11A_EADDR, ic->ic_myaddr); | 1000 | bwi_get_eaddr(sc, BWI_SPROM_11A_EADDR, ic->ic_myaddr); | |
1001 | if (IEEE80211_IS_MULTICAST(ic->ic_myaddr)) | 1001 | if (IEEE80211_IS_MULTICAST(ic->ic_myaddr)) | |
1002 | aprint_error_dev(sc->sc_dev, | 1002 | aprint_error_dev(sc->sc_dev, | |
1003 | "invalid MAC address: %s\n", | 1003 | "invalid MAC address: %s\n", | |
1004 | ether_sprintf(ic->ic_myaddr)); | 1004 | ether_sprintf(ic->ic_myaddr)); | |
1005 | } | 1005 | } | |
1006 | } else if (phy->phy_mode == IEEE80211_MODE_11A) { | 1006 | } else if (phy->phy_mode == IEEE80211_MODE_11A) { | |
1007 | /* TODO: 11A */ | 1007 | /* TODO: 11A */ | |
1008 | error = ENXIO; | 1008 | error = ENXIO; | |
1009 | goto fail; | 1009 | goto fail; | |
1010 | } else | 1010 | } else | |
1011 | panic("unknown phymode %d\n", phy->phy_mode); | 1011 | panic("unknown phymode %d\n", phy->phy_mode); | |
1012 | 1012 | |||
1013 | ic->ic_ifp = ifp; | 1013 | ic->ic_ifp = ifp; | |
1014 | ic->ic_caps = IEEE80211_C_SHSLOT | | 1014 | ic->ic_caps = IEEE80211_C_SHSLOT | | |
1015 | IEEE80211_C_SHPREAMBLE | | 1015 | IEEE80211_C_SHPREAMBLE | | |
1016 | IEEE80211_C_IBSS | | 1016 | IEEE80211_C_IBSS | | |
1017 | IEEE80211_C_HOSTAP | | 1017 | IEEE80211_C_HOSTAP | | |
1018 | IEEE80211_C_MONITOR; | 1018 | IEEE80211_C_MONITOR; | |
1019 | ic->ic_state = IEEE80211_S_INIT; | 1019 | ic->ic_state = IEEE80211_S_INIT; | |
1020 | ic->ic_opmode = IEEE80211_M_STA; | 1020 | ic->ic_opmode = IEEE80211_M_STA; | |
1021 | 1021 | |||
1022 | ic->ic_updateslot = bwi_updateslot; | 1022 | ic->ic_updateslot = bwi_updateslot; | |
1023 | 1023 | |||
1024 | error = if_initialize(ifp); | 1024 | error = if_initialize(ifp); | |
1025 | if (error != 0) { | 1025 | if (error != 0) { | |
1026 | aprint_error_dev(sc->sc_dev, "if_initialize failed(%d)\n", | 1026 | aprint_error_dev(sc->sc_dev, "if_initialize failed(%d)\n", | |
1027 | error); | 1027 | error); | |
1028 | goto fail; | 1028 | goto fail; | |
1029 | } | 1029 | } | |
1030 | ieee80211_ifattach(ic); | 1030 | ieee80211_ifattach(ic); | |
1031 | ifp->if_percpuq = if_percpuq_create(ifp); | 1031 | ifp->if_percpuq = if_percpuq_create(ifp); | |
1032 | if_register(ifp); | 1032 | if_register(ifp); | |
1033 | 1033 | |||
1034 | /* [TRC: XXX Not supported on NetBSD?] */ | 1034 | /* [TRC: XXX Not supported on NetBSD?] */ | |
1035 | /* ic->ic_flags_ext |= IEEE80211_FEXT_SWBMISS; */ | 1035 | /* ic->ic_flags_ext |= IEEE80211_FEXT_SWBMISS; */ | |
1036 | 1036 | |||
1037 | sc->sc_newstate = ic->ic_newstate; | 1037 | sc->sc_newstate = ic->ic_newstate; | |
1038 | ic->ic_newstate = bwi_newstate; | 1038 | ic->ic_newstate = bwi_newstate; | |
1039 | /* [TRC: XXX amrr] */ | 1039 | /* [TRC: XXX amrr] */ | |
1040 | ic->ic_newassoc = bwi_newassoc; | 1040 | ic->ic_newassoc = bwi_newassoc; | |
1041 | ic->ic_node_alloc = bwi_node_alloc; | 1041 | ic->ic_node_alloc = bwi_node_alloc; | |
1042 | 1042 | |||
1043 | ieee80211_media_init(ic, bwi_media_change, ieee80211_media_status); | 1043 | ieee80211_media_init(ic, bwi_media_change, ieee80211_media_status); | |
1044 | 1044 | |||
1045 | bpf_attach2(ifp, DLT_IEEE802_11_RADIO, | 1045 | bpf_attach2(ifp, DLT_IEEE802_11_RADIO, | |
1046 | sizeof(struct ieee80211_frame) + IEEE80211_RADIOTAP_HDRLEN, | 1046 | sizeof(struct ieee80211_frame) + IEEE80211_RADIOTAP_HDRLEN, | |
1047 | &sc->sc_drvbpf); | 1047 | &sc->sc_drvbpf); | |
1048 | 1048 | |||
1049 | /* [TRC: XXX DragonFlyBSD rounds this up to a multiple of | 1049 | /* [TRC: XXX DragonFlyBSD rounds this up to a multiple of | |
1050 | sizeof(uint32_t). Should we?] */ | 1050 | sizeof(uint32_t). Should we?] */ | |
@@ -6424,3337 +6424,3337 @@ bwi_power_on(struct bwi_softc *sc, int w | @@ -6424,3337 +6424,3337 @@ bwi_power_on(struct bwi_softc *sc, int w | |||
6424 | 6424 | |||
6425 | DPRINTF(sc, BWI_DBG_MISC, "%s\n", __func__); | 6425 | DPRINTF(sc, BWI_DBG_MISC, "%s\n", __func__); | |
6426 | 6426 | |||
6427 | gpio_in = (sc->sc_conf_read)(sc, BWI_PCIR_GPIO_IN); | 6427 | gpio_in = (sc->sc_conf_read)(sc, BWI_PCIR_GPIO_IN); | |
6428 | if (gpio_in & BWI_PCIM_GPIO_PWR_ON) | 6428 | if (gpio_in & BWI_PCIM_GPIO_PWR_ON) | |
6429 | goto back; | 6429 | goto back; | |
6430 | 6430 | |||
6431 | gpio_out = (sc->sc_conf_read)(sc, BWI_PCIR_GPIO_OUT); | 6431 | gpio_out = (sc->sc_conf_read)(sc, BWI_PCIR_GPIO_OUT); | |
6432 | gpio_en = (sc->sc_conf_read)(sc, BWI_PCIR_GPIO_ENABLE); | 6432 | gpio_en = (sc->sc_conf_read)(sc, BWI_PCIR_GPIO_ENABLE); | |
6433 | 6433 | |||
6434 | gpio_out |= BWI_PCIM_GPIO_PWR_ON; | 6434 | gpio_out |= BWI_PCIM_GPIO_PWR_ON; | |
6435 | gpio_en |= BWI_PCIM_GPIO_PWR_ON; | 6435 | gpio_en |= BWI_PCIM_GPIO_PWR_ON; | |
6436 | if (with_pll) { | 6436 | if (with_pll) { | |
6437 | /* Turn off PLL first */ | 6437 | /* Turn off PLL first */ | |
6438 | gpio_out |= BWI_PCIM_GPIO_PLL_PWR_OFF; | 6438 | gpio_out |= BWI_PCIM_GPIO_PLL_PWR_OFF; | |
6439 | gpio_en |= BWI_PCIM_GPIO_PLL_PWR_OFF; | 6439 | gpio_en |= BWI_PCIM_GPIO_PLL_PWR_OFF; | |
6440 | } | 6440 | } | |
6441 | 6441 | |||
6442 | (sc->sc_conf_write)(sc, BWI_PCIR_GPIO_OUT, gpio_out); | 6442 | (sc->sc_conf_write)(sc, BWI_PCIR_GPIO_OUT, gpio_out); | |
6443 | (sc->sc_conf_write)(sc, BWI_PCIR_GPIO_ENABLE, gpio_en); | 6443 | (sc->sc_conf_write)(sc, BWI_PCIR_GPIO_ENABLE, gpio_en); | |
6444 | DELAY(1000); | 6444 | DELAY(1000); | |
6445 | 6445 | |||
6446 | if (with_pll) { | 6446 | if (with_pll) { | |
6447 | /* Turn on PLL */ | 6447 | /* Turn on PLL */ | |
6448 | gpio_out &= ~BWI_PCIM_GPIO_PLL_PWR_OFF; | 6448 | gpio_out &= ~BWI_PCIM_GPIO_PLL_PWR_OFF; | |
6449 | (sc->sc_conf_write)(sc, BWI_PCIR_GPIO_OUT, gpio_out); | 6449 | (sc->sc_conf_write)(sc, BWI_PCIR_GPIO_OUT, gpio_out); | |
6450 | DELAY(5000); | 6450 | DELAY(5000); | |
6451 | } | 6451 | } | |
6452 | 6452 | |||
6453 | back: | 6453 | back: | |
6454 | /* [TRC: XXX This looks totally wrong -- what's PCI doing in here?] */ | 6454 | /* [TRC: XXX This looks totally wrong -- what's PCI doing in here?] */ | |
6455 | /* Clear "Signaled Target Abort" */ | 6455 | /* Clear "Signaled Target Abort" */ | |
6456 | status = (sc->sc_conf_read)(sc, PCI_COMMAND_STATUS_REG); | 6456 | status = (sc->sc_conf_read)(sc, PCI_COMMAND_STATUS_REG); | |
6457 | status &= ~PCI_STATUS_TARGET_TARGET_ABORT; | 6457 | status &= ~PCI_STATUS_TARGET_TARGET_ABORT; | |
6458 | (sc->sc_conf_write)(sc, PCI_COMMAND_STATUS_REG, status); | 6458 | (sc->sc_conf_write)(sc, PCI_COMMAND_STATUS_REG, status); | |
6459 | } | 6459 | } | |
6460 | 6460 | |||
6461 | static int | 6461 | static int | |
6462 | bwi_power_off(struct bwi_softc *sc, int with_pll) | 6462 | bwi_power_off(struct bwi_softc *sc, int with_pll) | |
6463 | { | 6463 | { | |
6464 | uint32_t gpio_out, gpio_en; | 6464 | uint32_t gpio_out, gpio_en; | |
6465 | 6465 | |||
6466 | DPRINTF(sc, BWI_DBG_MISC, "%s\n", __func__); | 6466 | DPRINTF(sc, BWI_DBG_MISC, "%s\n", __func__); | |
6467 | 6467 | |||
6468 | (sc->sc_conf_read)(sc, BWI_PCIR_GPIO_IN); /* dummy read */ | 6468 | (sc->sc_conf_read)(sc, BWI_PCIR_GPIO_IN); /* dummy read */ | |
6469 | gpio_out = (sc->sc_conf_read)(sc, BWI_PCIR_GPIO_OUT); | 6469 | gpio_out = (sc->sc_conf_read)(sc, BWI_PCIR_GPIO_OUT); | |
6470 | gpio_en = (sc->sc_conf_read)(sc, BWI_PCIR_GPIO_ENABLE); | 6470 | gpio_en = (sc->sc_conf_read)(sc, BWI_PCIR_GPIO_ENABLE); | |
6471 | 6471 | |||
6472 | gpio_out &= ~BWI_PCIM_GPIO_PWR_ON; | 6472 | gpio_out &= ~BWI_PCIM_GPIO_PWR_ON; | |
6473 | gpio_en |= BWI_PCIM_GPIO_PWR_ON; | 6473 | gpio_en |= BWI_PCIM_GPIO_PWR_ON; | |
6474 | if (with_pll) { | 6474 | if (with_pll) { | |
6475 | gpio_out |= BWI_PCIM_GPIO_PLL_PWR_OFF; | 6475 | gpio_out |= BWI_PCIM_GPIO_PLL_PWR_OFF; | |
6476 | gpio_en |= BWI_PCIM_GPIO_PLL_PWR_OFF; | 6476 | gpio_en |= BWI_PCIM_GPIO_PLL_PWR_OFF; | |
6477 | } | 6477 | } | |
6478 | 6478 | |||
6479 | (sc->sc_conf_write)(sc, BWI_PCIR_GPIO_OUT, gpio_out); | 6479 | (sc->sc_conf_write)(sc, BWI_PCIR_GPIO_OUT, gpio_out); | |
6480 | (sc->sc_conf_write)(sc, BWI_PCIR_GPIO_ENABLE, gpio_en); | 6480 | (sc->sc_conf_write)(sc, BWI_PCIR_GPIO_ENABLE, gpio_en); | |
6481 | 6481 | |||
6482 | return (0); | 6482 | return (0); | |
6483 | } | 6483 | } | |
6484 | 6484 | |||
6485 | static int | 6485 | static int | |
6486 | bwi_regwin_switch(struct bwi_softc *sc, struct bwi_regwin *rw, | 6486 | bwi_regwin_switch(struct bwi_softc *sc, struct bwi_regwin *rw, | |
6487 | struct bwi_regwin **old_rw) | 6487 | struct bwi_regwin **old_rw) | |
6488 | { | 6488 | { | |
6489 | int error; | 6489 | int error; | |
6490 | 6490 | |||
6491 | if (old_rw != NULL) | 6491 | if (old_rw != NULL) | |
6492 | *old_rw = NULL; | 6492 | *old_rw = NULL; | |
6493 | 6493 | |||
6494 | if (!BWI_REGWIN_EXIST(rw)) | 6494 | if (!BWI_REGWIN_EXIST(rw)) | |
6495 | return (EINVAL); | 6495 | return (EINVAL); | |
6496 | 6496 | |||
6497 | if (sc->sc_cur_regwin != rw) { | 6497 | if (sc->sc_cur_regwin != rw) { | |
6498 | error = bwi_regwin_select(sc, rw->rw_id); | 6498 | error = bwi_regwin_select(sc, rw->rw_id); | |
6499 | if (error) { | 6499 | if (error) { | |
6500 | aprint_error_dev(sc->sc_dev, | 6500 | aprint_error_dev(sc->sc_dev, | |
6501 | "can't select regwin %d\n", rw->rw_id); | 6501 | "can't select regwin %d\n", rw->rw_id); | |
6502 | return (error); | 6502 | return (error); | |
6503 | } | 6503 | } | |
6504 | } | 6504 | } | |
6505 | 6505 | |||
6506 | if (old_rw != NULL) | 6506 | if (old_rw != NULL) | |
6507 | *old_rw = sc->sc_cur_regwin; | 6507 | *old_rw = sc->sc_cur_regwin; | |
6508 | sc->sc_cur_regwin = rw; | 6508 | sc->sc_cur_regwin = rw; | |
6509 | 6509 | |||
6510 | return (0); | 6510 | return (0); | |
6511 | } | 6511 | } | |
6512 | 6512 | |||
6513 | static int | 6513 | static int | |
6514 | bwi_regwin_select(struct bwi_softc *sc, int id) | 6514 | bwi_regwin_select(struct bwi_softc *sc, int id) | |
6515 | { | 6515 | { | |
6516 | uint32_t win = BWI_PCIM_REGWIN(id); | 6516 | uint32_t win = BWI_PCIM_REGWIN(id); | |
6517 | int i; | 6517 | int i; | |
6518 | 6518 | |||
6519 | #define RETRY_MAX 50 | 6519 | #define RETRY_MAX 50 | |
6520 | for (i = 0; i < RETRY_MAX; ++i) { | 6520 | for (i = 0; i < RETRY_MAX; ++i) { | |
6521 | (sc->sc_conf_write)(sc, BWI_PCIR_SEL_REGWIN, win); | 6521 | (sc->sc_conf_write)(sc, BWI_PCIR_SEL_REGWIN, win); | |
6522 | if ((sc->sc_conf_read)(sc, BWI_PCIR_SEL_REGWIN) == win) | 6522 | if ((sc->sc_conf_read)(sc, BWI_PCIR_SEL_REGWIN) == win) | |
6523 | return (0); | 6523 | return (0); | |
6524 | DELAY(10); | 6524 | DELAY(10); | |
6525 | } | 6525 | } | |
6526 | #undef RETRY_MAX | 6526 | #undef RETRY_MAX | |
6527 | 6527 | |||
6528 | return (ENXIO); | 6528 | return (ENXIO); | |
6529 | } | 6529 | } | |
6530 | 6530 | |||
6531 | static void | 6531 | static void | |
6532 | bwi_regwin_info(struct bwi_softc *sc, uint16_t *type, uint8_t *rev) | 6532 | bwi_regwin_info(struct bwi_softc *sc, uint16_t *type, uint8_t *rev) | |
6533 | { | 6533 | { | |
6534 | uint32_t val; | 6534 | uint32_t val; | |
6535 | 6535 | |||
6536 | val = CSR_READ_4(sc, BWI_ID_HI); | 6536 | val = CSR_READ_4(sc, BWI_ID_HI); | |
6537 | *type = BWI_ID_HI_REGWIN_TYPE(val); | 6537 | *type = BWI_ID_HI_REGWIN_TYPE(val); | |
6538 | *rev = BWI_ID_HI_REGWIN_REV(val); | 6538 | *rev = BWI_ID_HI_REGWIN_REV(val); | |
6539 | 6539 | |||
6540 | DPRINTF(sc, BWI_DBG_ATTACH, "regwin: type 0x%03x, rev %d," | 6540 | DPRINTF(sc, BWI_DBG_ATTACH, "regwin: type 0x%03x, rev %d," | |
6541 | " vendor 0x%04x\n", *type, *rev, | 6541 | " vendor 0x%04x\n", *type, *rev, | |
6542 | __SHIFTOUT(val, BWI_ID_HI_REGWIN_VENDOR_MASK)); | 6542 | __SHIFTOUT(val, BWI_ID_HI_REGWIN_VENDOR_MASK)); | |
6543 | } | 6543 | } | |
6544 | 6544 | |||
6545 | static void | 6545 | static void | |
6546 | bwi_led_attach(struct bwi_softc *sc) | 6546 | bwi_led_attach(struct bwi_softc *sc) | |
6547 | { | 6547 | { | |
6548 | const uint8_t *led_act = NULL; | 6548 | const uint8_t *led_act = NULL; | |
6549 | uint16_t gpio, val[BWI_LED_MAX]; | 6549 | uint16_t gpio, val[BWI_LED_MAX]; | |
6550 | int i; | 6550 | int i; | |
6551 | 6551 | |||
6552 | for (i = 0; i < __arraycount(bwi_vendor_led_act); ++i) { | 6552 | for (i = 0; i < __arraycount(bwi_vendor_led_act); ++i) { | |
6553 | if (sc->sc_pci_subvid == bwi_vendor_led_act[i].vid) { | 6553 | if (sc->sc_pci_subvid == bwi_vendor_led_act[i].vid) { | |
6554 | led_act = bwi_vendor_led_act[i].led_act; | 6554 | led_act = bwi_vendor_led_act[i].led_act; | |
6555 | break; | 6555 | break; | |
6556 | } | 6556 | } | |
6557 | } | 6557 | } | |
6558 | if (led_act == NULL) | 6558 | if (led_act == NULL) | |
6559 | led_act = bwi_default_led_act; | 6559 | led_act = bwi_default_led_act; | |
6560 | 6560 | |||
6561 | gpio = bwi_read_sprom(sc, BWI_SPROM_GPIO01); | 6561 | gpio = bwi_read_sprom(sc, BWI_SPROM_GPIO01); | |
6562 | val[0] = __SHIFTOUT(gpio, BWI_SPROM_GPIO_0); | 6562 | val[0] = __SHIFTOUT(gpio, BWI_SPROM_GPIO_0); | |
6563 | val[1] = __SHIFTOUT(gpio, BWI_SPROM_GPIO_1); | 6563 | val[1] = __SHIFTOUT(gpio, BWI_SPROM_GPIO_1); | |
6564 | 6564 | |||
6565 | gpio = bwi_read_sprom(sc, BWI_SPROM_GPIO23); | 6565 | gpio = bwi_read_sprom(sc, BWI_SPROM_GPIO23); | |
6566 | val[2] = __SHIFTOUT(gpio, BWI_SPROM_GPIO_2); | 6566 | val[2] = __SHIFTOUT(gpio, BWI_SPROM_GPIO_2); | |
6567 | val[3] = __SHIFTOUT(gpio, BWI_SPROM_GPIO_3); | 6567 | val[3] = __SHIFTOUT(gpio, BWI_SPROM_GPIO_3); | |
6568 | 6568 | |||
6569 | for (i = 0; i < BWI_LED_MAX; ++i) { | 6569 | for (i = 0; i < BWI_LED_MAX; ++i) { | |
6570 | struct bwi_led *led = &sc->sc_leds[i]; | 6570 | struct bwi_led *led = &sc->sc_leds[i]; | |
6571 | 6571 | |||
6572 | if (val[i] == 0xff) { | 6572 | if (val[i] == 0xff) { | |
6573 | led->l_act = led_act[i]; | 6573 | led->l_act = led_act[i]; | |
6574 | } else { | 6574 | } else { | |
6575 | if (val[i] & BWI_LED_ACT_LOW) | 6575 | if (val[i] & BWI_LED_ACT_LOW) | |
6576 | led->l_flags |= BWI_LED_F_ACTLOW; | 6576 | led->l_flags |= BWI_LED_F_ACTLOW; | |
6577 | led->l_act = __SHIFTOUT(val[i], BWI_LED_ACT_MASK); | 6577 | led->l_act = __SHIFTOUT(val[i], BWI_LED_ACT_MASK); | |
6578 | } | 6578 | } | |
6579 | led->l_mask = (1 << i); | 6579 | led->l_mask = (1 << i); | |
6580 | 6580 | |||
6581 | if (led->l_act == BWI_LED_ACT_BLINK_SLOW || | 6581 | if (led->l_act == BWI_LED_ACT_BLINK_SLOW || | |
6582 | led->l_act == BWI_LED_ACT_BLINK_POLL || | 6582 | led->l_act == BWI_LED_ACT_BLINK_POLL || | |
6583 | led->l_act == BWI_LED_ACT_BLINK) { | 6583 | led->l_act == BWI_LED_ACT_BLINK) { | |
6584 | led->l_flags |= BWI_LED_F_BLINK; | 6584 | led->l_flags |= BWI_LED_F_BLINK; | |
6585 | if (led->l_act == BWI_LED_ACT_BLINK_POLL) | 6585 | if (led->l_act == BWI_LED_ACT_BLINK_POLL) | |
6586 | led->l_flags |= BWI_LED_F_POLLABLE; | 6586 | led->l_flags |= BWI_LED_F_POLLABLE; | |
6587 | else if (led->l_act == BWI_LED_ACT_BLINK_SLOW) | 6587 | else if (led->l_act == BWI_LED_ACT_BLINK_SLOW) | |
6588 | led->l_flags |= BWI_LED_F_SLOW; | 6588 | led->l_flags |= BWI_LED_F_SLOW; | |
6589 | 6589 | |||
6590 | if (sc->sc_blink_led == NULL) { | 6590 | if (sc->sc_blink_led == NULL) { | |
6591 | sc->sc_blink_led = led; | 6591 | sc->sc_blink_led = led; | |
6592 | if (led->l_flags & BWI_LED_F_SLOW) | 6592 | if (led->l_flags & BWI_LED_F_SLOW) | |
6593 | BWI_LED_SLOWDOWN(sc->sc_led_idle); | 6593 | BWI_LED_SLOWDOWN(sc->sc_led_idle); | |
6594 | } | 6594 | } | |
6595 | } | 6595 | } | |
6596 | 6596 | |||
6597 | DPRINTF(sc, BWI_DBG_LED | BWI_DBG_ATTACH, | 6597 | DPRINTF(sc, BWI_DBG_LED | BWI_DBG_ATTACH, | |
6598 | "%dth led, act %d, lowact %d\n", i, led->l_act, | 6598 | "%dth led, act %d, lowact %d\n", i, led->l_act, | |
6599 | led->l_flags & BWI_LED_F_ACTLOW); | 6599 | led->l_flags & BWI_LED_F_ACTLOW); | |
6600 | } | 6600 | } | |
6601 | callout_init(&sc->sc_led_blink_ch, 0); | 6601 | callout_init(&sc->sc_led_blink_ch, 0); | |
6602 | } | 6602 | } | |
6603 | 6603 | |||
6604 | static uint16_t | 6604 | static uint16_t | |
6605 | bwi_led_onoff(const struct bwi_led *led, uint16_t val, int on) | 6605 | bwi_led_onoff(const struct bwi_led *led, uint16_t val, int on) | |
6606 | { | 6606 | { | |
6607 | if (led->l_flags & BWI_LED_F_ACTLOW) | 6607 | if (led->l_flags & BWI_LED_F_ACTLOW) | |
6608 | on = !on; | 6608 | on = !on; | |
6609 | if (on) | 6609 | if (on) | |
6610 | val |= led->l_mask; | 6610 | val |= led->l_mask; | |
6611 | else | 6611 | else | |
6612 | val &= ~led->l_mask; | 6612 | val &= ~led->l_mask; | |
6613 | 6613 | |||
6614 | return (val); | 6614 | return (val); | |
6615 | } | 6615 | } | |
6616 | 6616 | |||
6617 | static void | 6617 | static void | |
6618 | bwi_led_newstate(struct bwi_softc *sc, enum ieee80211_state nstate) | 6618 | bwi_led_newstate(struct bwi_softc *sc, enum ieee80211_state nstate) | |
6619 | { | 6619 | { | |
6620 | struct ieee80211com *ic = &sc->sc_ic; | 6620 | struct ieee80211com *ic = &sc->sc_ic; | |
6621 | struct ifnet *ifp = &sc->sc_if; | 6621 | struct ifnet *ifp = &sc->sc_if; | |
6622 | uint16_t val; | 6622 | uint16_t val; | |
6623 | int i; | 6623 | int i; | |
6624 | 6624 | |||
6625 | if (nstate == IEEE80211_S_INIT) { | 6625 | if (nstate == IEEE80211_S_INIT) { | |
6626 | callout_stop(&sc->sc_led_blink_ch); | 6626 | callout_stop(&sc->sc_led_blink_ch); | |
6627 | sc->sc_led_blinking = 0; | 6627 | sc->sc_led_blinking = 0; | |
6628 | } | 6628 | } | |
6629 | 6629 | |||
6630 | if ((ifp->if_flags & IFF_RUNNING) == 0) | 6630 | if ((ifp->if_flags & IFF_RUNNING) == 0) | |
6631 | return; | 6631 | return; | |
6632 | 6632 | |||
6633 | val = CSR_READ_2(sc, BWI_MAC_GPIO_CTRL); | 6633 | val = CSR_READ_2(sc, BWI_MAC_GPIO_CTRL); | |
6634 | for (i = 0; i < BWI_LED_MAX; ++i) { | 6634 | for (i = 0; i < BWI_LED_MAX; ++i) { | |
6635 | struct bwi_led *led = &sc->sc_leds[i]; | 6635 | struct bwi_led *led = &sc->sc_leds[i]; | |
6636 | int on; | 6636 | int on; | |
6637 | 6637 | |||
6638 | if (led->l_act == BWI_LED_ACT_UNKN || | 6638 | if (led->l_act == BWI_LED_ACT_UNKN || | |
6639 | led->l_act == BWI_LED_ACT_NULL) | 6639 | led->l_act == BWI_LED_ACT_NULL) | |
6640 | continue; | 6640 | continue; | |
6641 | 6641 | |||
6642 | if ((led->l_flags & BWI_LED_F_BLINK) && | 6642 | if ((led->l_flags & BWI_LED_F_BLINK) && | |
6643 | nstate != IEEE80211_S_INIT) | 6643 | nstate != IEEE80211_S_INIT) | |
6644 | continue; | 6644 | continue; | |
6645 | 6645 | |||
6646 | switch (led->l_act) { | 6646 | switch (led->l_act) { | |
6647 | case BWI_LED_ACT_ON: /* Always on */ | 6647 | case BWI_LED_ACT_ON: /* Always on */ | |
6648 | on = 1; | 6648 | on = 1; | |
6649 | break; | 6649 | break; | |
6650 | case BWI_LED_ACT_OFF: /* Always off */ | 6650 | case BWI_LED_ACT_OFF: /* Always off */ | |
6651 | case BWI_LED_ACT_5GHZ: /* TODO: 11A */ | 6651 | case BWI_LED_ACT_5GHZ: /* TODO: 11A */ | |
6652 | on = 0; | 6652 | on = 0; | |
6653 | break; | 6653 | break; | |
6654 | default: | 6654 | default: | |
6655 | on = 1; | 6655 | on = 1; | |
6656 | switch (nstate) { | 6656 | switch (nstate) { | |
6657 | case IEEE80211_S_INIT: | 6657 | case IEEE80211_S_INIT: | |
6658 | on = 0; | 6658 | on = 0; | |
6659 | break; | 6659 | break; | |
6660 | case IEEE80211_S_RUN: | 6660 | case IEEE80211_S_RUN: | |
6661 | if (led->l_act == BWI_LED_ACT_11G && | 6661 | if (led->l_act == BWI_LED_ACT_11G && | |
6662 | ic->ic_curmode != IEEE80211_MODE_11G) | 6662 | ic->ic_curmode != IEEE80211_MODE_11G) | |
6663 | on = 0; | 6663 | on = 0; | |
6664 | break; | 6664 | break; | |
6665 | default: | 6665 | default: | |
6666 | if (led->l_act == BWI_LED_ACT_ASSOC) | 6666 | if (led->l_act == BWI_LED_ACT_ASSOC) | |
6667 | on = 0; | 6667 | on = 0; | |
6668 | break; | 6668 | break; | |
6669 | } | 6669 | } | |
6670 | break; | 6670 | break; | |
6671 | } | 6671 | } | |
6672 | 6672 | |||
6673 | val = bwi_led_onoff(led, val, on); | 6673 | val = bwi_led_onoff(led, val, on); | |
6674 | } | 6674 | } | |
6675 | CSR_WRITE_2(sc, BWI_MAC_GPIO_CTRL, val); | 6675 | CSR_WRITE_2(sc, BWI_MAC_GPIO_CTRL, val); | |
6676 | } | 6676 | } | |
6677 | 6677 | |||
6678 | static void | 6678 | static void | |
6679 | bwi_led_event(struct bwi_softc *sc, int event) | 6679 | bwi_led_event(struct bwi_softc *sc, int event) | |
6680 | { | 6680 | { | |
6681 | struct bwi_led *led = sc->sc_blink_led; | 6681 | struct bwi_led *led = sc->sc_blink_led; | |
6682 | int rate; | 6682 | int rate; | |
6683 | 6683 | |||
6684 | if (event == BWI_LED_EVENT_POLL) { | 6684 | if (event == BWI_LED_EVENT_POLL) { | |
6685 | if ((led->l_flags & BWI_LED_F_POLLABLE) == 0) | 6685 | if ((led->l_flags & BWI_LED_F_POLLABLE) == 0) | |
6686 | return; | 6686 | return; | |
6687 | if (ticks - sc->sc_led_ticks < sc->sc_led_idle) | 6687 | if (ticks - sc->sc_led_ticks < sc->sc_led_idle) | |
6688 | return; | 6688 | return; | |
6689 | } | 6689 | } | |
6690 | 6690 | |||
6691 | sc->sc_led_ticks = ticks; | 6691 | sc->sc_led_ticks = ticks; | |
6692 | if (sc->sc_led_blinking) | 6692 | if (sc->sc_led_blinking) | |
6693 | return; | 6693 | return; | |
6694 | 6694 | |||
6695 | switch (event) { | 6695 | switch (event) { | |
6696 | case BWI_LED_EVENT_RX: | 6696 | case BWI_LED_EVENT_RX: | |
6697 | rate = sc->sc_rx_rate; | 6697 | rate = sc->sc_rx_rate; | |
6698 | break; | 6698 | break; | |
6699 | case BWI_LED_EVENT_TX: | 6699 | case BWI_LED_EVENT_TX: | |
6700 | rate = sc->sc_tx_rate; | 6700 | rate = sc->sc_tx_rate; | |
6701 | break; | 6701 | break; | |
6702 | case BWI_LED_EVENT_POLL: | 6702 | case BWI_LED_EVENT_POLL: | |
6703 | rate = 0; | 6703 | rate = 0; | |
6704 | break; | 6704 | break; | |
6705 | default: | 6705 | default: | |
6706 | panic("unknown LED event %d\n", event); | 6706 | panic("unknown LED event %d\n", event); | |
6707 | break; | 6707 | break; | |
6708 | } | 6708 | } | |
6709 | bwi_led_blink_start(sc, bwi_led_duration[rate].on_dur, | 6709 | bwi_led_blink_start(sc, bwi_led_duration[rate].on_dur, | |
6710 | bwi_led_duration[rate].off_dur); | 6710 | bwi_led_duration[rate].off_dur); | |
6711 | } | 6711 | } | |
6712 | 6712 | |||
6713 | static void | 6713 | static void | |
6714 | bwi_led_blink_start(struct bwi_softc *sc, int on_dur, int off_dur) | 6714 | bwi_led_blink_start(struct bwi_softc *sc, int on_dur, int off_dur) | |
6715 | { | 6715 | { | |
6716 | struct bwi_led *led = sc->sc_blink_led; | 6716 | struct bwi_led *led = sc->sc_blink_led; | |
6717 | uint16_t val; | 6717 | uint16_t val; | |
6718 | 6718 | |||
6719 | val = CSR_READ_2(sc, BWI_MAC_GPIO_CTRL); | 6719 | val = CSR_READ_2(sc, BWI_MAC_GPIO_CTRL); | |
6720 | val = bwi_led_onoff(led, val, 1); | 6720 | val = bwi_led_onoff(led, val, 1); | |
6721 | CSR_WRITE_2(sc, BWI_MAC_GPIO_CTRL, val); | 6721 | CSR_WRITE_2(sc, BWI_MAC_GPIO_CTRL, val); | |
6722 | 6722 | |||
6723 | if (led->l_flags & BWI_LED_F_SLOW) { | 6723 | if (led->l_flags & BWI_LED_F_SLOW) { | |
6724 | BWI_LED_SLOWDOWN(on_dur); | 6724 | BWI_LED_SLOWDOWN(on_dur); | |
6725 | BWI_LED_SLOWDOWN(off_dur); | 6725 | BWI_LED_SLOWDOWN(off_dur); | |
6726 | } | 6726 | } | |
6727 | 6727 | |||
6728 | sc->sc_led_blinking = 1; | 6728 | sc->sc_led_blinking = 1; | |
6729 | sc->sc_led_blink_offdur = off_dur; | 6729 | sc->sc_led_blink_offdur = off_dur; | |
6730 | 6730 | |||
6731 | callout_reset(&sc->sc_led_blink_ch, on_dur, bwi_led_blink_next, sc); | 6731 | callout_reset(&sc->sc_led_blink_ch, on_dur, bwi_led_blink_next, sc); | |
6732 | } | 6732 | } | |
6733 | 6733 | |||
6734 | static void | 6734 | static void | |
6735 | bwi_led_blink_next(void *xsc) | 6735 | bwi_led_blink_next(void *xsc) | |
6736 | { | 6736 | { | |
6737 | struct bwi_softc *sc = xsc; | 6737 | struct bwi_softc *sc = xsc; | |
6738 | uint16_t val; | 6738 | uint16_t val; | |
6739 | 6739 | |||
6740 | val = CSR_READ_2(sc, BWI_MAC_GPIO_CTRL); | 6740 | val = CSR_READ_2(sc, BWI_MAC_GPIO_CTRL); | |
6741 | val = bwi_led_onoff(sc->sc_blink_led, val, 0); | 6741 | val = bwi_led_onoff(sc->sc_blink_led, val, 0); | |
6742 | CSR_WRITE_2(sc, BWI_MAC_GPIO_CTRL, val); | 6742 | CSR_WRITE_2(sc, BWI_MAC_GPIO_CTRL, val); | |
6743 | 6743 | |||
6744 | callout_reset(&sc->sc_led_blink_ch, sc->sc_led_blink_offdur, | 6744 | callout_reset(&sc->sc_led_blink_ch, sc->sc_led_blink_offdur, | |
6745 | bwi_led_blink_end, sc); | 6745 | bwi_led_blink_end, sc); | |
6746 | } | 6746 | } | |
6747 | 6747 | |||
6748 | static void | 6748 | static void | |
6749 | bwi_led_blink_end(void *xsc) | 6749 | bwi_led_blink_end(void *xsc) | |
6750 | { | 6750 | { | |
6751 | struct bwi_softc *sc = xsc; | 6751 | struct bwi_softc *sc = xsc; | |
6752 | 6752 | |||
6753 | sc->sc_led_blinking = 0; | 6753 | sc->sc_led_blinking = 0; | |
6754 | } | 6754 | } | |
6755 | 6755 | |||
6756 | static int | 6756 | static int | |
6757 | bwi_bbp_attach(struct bwi_softc *sc) | 6757 | bwi_bbp_attach(struct bwi_softc *sc) | |
6758 | { | 6758 | { | |
6759 | uint16_t bbp_id, rw_type; | 6759 | uint16_t bbp_id, rw_type; | |
6760 | uint8_t rw_rev; | 6760 | uint8_t rw_rev; | |
6761 | uint32_t info; | 6761 | uint32_t info; | |
6762 | int error, nregwin, i; | 6762 | int error, nregwin, i; | |
6763 | 6763 | |||
6764 | /* | 6764 | /* | |
6765 | * Get 0th regwin information | 6765 | * Get 0th regwin information | |
6766 | * NOTE: 0th regwin should exist | 6766 | * NOTE: 0th regwin should exist | |
6767 | */ | 6767 | */ | |
6768 | error = bwi_regwin_select(sc, 0); | 6768 | error = bwi_regwin_select(sc, 0); | |
6769 | if (error) { | 6769 | if (error) { | |
6770 | aprint_error_dev(sc->sc_dev, "can't select regwin 0\n"); | 6770 | aprint_error_dev(sc->sc_dev, "can't select regwin 0\n"); | |
6771 | return (error); | 6771 | return (error); | |
6772 | } | 6772 | } | |
6773 | bwi_regwin_info(sc, &rw_type, &rw_rev); | 6773 | bwi_regwin_info(sc, &rw_type, &rw_rev); | |
6774 | 6774 | |||
6775 | /* | 6775 | /* | |
6776 | * Find out BBP id | 6776 | * Find out BBP id | |
6777 | */ | 6777 | */ | |
6778 | bbp_id = 0; | 6778 | bbp_id = 0; | |
6779 | info = 0; | 6779 | info = 0; | |
6780 | if (rw_type == BWI_REGWIN_T_COM) { | 6780 | if (rw_type == BWI_REGWIN_T_COM) { | |
6781 | info = CSR_READ_4(sc, BWI_INFO); | 6781 | info = CSR_READ_4(sc, BWI_INFO); | |
6782 | bbp_id = __SHIFTOUT(info, BWI_INFO_BBPID_MASK); | 6782 | bbp_id = __SHIFTOUT(info, BWI_INFO_BBPID_MASK); | |
6783 | 6783 | |||
6784 | BWI_CREATE_REGWIN(&sc->sc_com_regwin, 0, rw_type, rw_rev); | 6784 | BWI_CREATE_REGWIN(&sc->sc_com_regwin, 0, rw_type, rw_rev); | |
6785 | 6785 | |||
6786 | sc->sc_cap = CSR_READ_4(sc, BWI_CAPABILITY); | 6786 | sc->sc_cap = CSR_READ_4(sc, BWI_CAPABILITY); | |
6787 | } else { | 6787 | } else { | |
6788 | uint16_t did = sc->sc_pci_did; | 6788 | uint16_t did = sc->sc_pci_did; | |
6789 | uint8_t revid = sc->sc_pci_revid; | 6789 | uint8_t revid = sc->sc_pci_revid; | |
6790 | 6790 | |||
6791 | for (i = 0; i < __arraycount(bwi_bbpid_map); ++i) { | 6791 | for (i = 0; i < __arraycount(bwi_bbpid_map); ++i) { | |
6792 | if (did >= bwi_bbpid_map[i].did_min && | 6792 | if (did >= bwi_bbpid_map[i].did_min && | |
6793 | did <= bwi_bbpid_map[i].did_max) { | 6793 | did <= bwi_bbpid_map[i].did_max) { | |
6794 | bbp_id = bwi_bbpid_map[i].bbp_id; | 6794 | bbp_id = bwi_bbpid_map[i].bbp_id; | |
6795 | break; | 6795 | break; | |
6796 | } | 6796 | } | |
6797 | } | 6797 | } | |
6798 | if (bbp_id == 0) { | 6798 | if (bbp_id == 0) { | |
6799 | aprint_error_dev(sc->sc_dev, "no BBP id for device id" | 6799 | aprint_error_dev(sc->sc_dev, "no BBP id for device id" | |
6800 | " 0x%04x\n", did); | 6800 | " 0x%04x\n", did); | |
6801 | return (ENXIO); | 6801 | return (ENXIO); | |
6802 | } | 6802 | } | |
6803 | 6803 | |||
6804 | info = __SHIFTIN(revid, BWI_INFO_BBPREV_MASK) | | 6804 | info = __SHIFTIN(revid, BWI_INFO_BBPREV_MASK) | | |
6805 | __SHIFTIN(0, BWI_INFO_BBPPKG_MASK); | 6805 | __SHIFTIN(0, BWI_INFO_BBPPKG_MASK); | |
6806 | } | 6806 | } | |
6807 | 6807 | |||
6808 | /* | 6808 | /* | |
6809 | * Find out number of regwins | 6809 | * Find out number of regwins | |
6810 | */ | 6810 | */ | |
6811 | nregwin = 0; | 6811 | nregwin = 0; | |
6812 | if (rw_type == BWI_REGWIN_T_COM && rw_rev >= 4) { | 6812 | if (rw_type == BWI_REGWIN_T_COM && rw_rev >= 4) { | |
6813 | nregwin = __SHIFTOUT(info, BWI_INFO_NREGWIN_MASK); | 6813 | nregwin = __SHIFTOUT(info, BWI_INFO_NREGWIN_MASK); | |
6814 | } else { | 6814 | } else { | |
6815 | for (i = 0; i < __arraycount(bwi_regwin_count); ++i) { | 6815 | for (i = 0; i < __arraycount(bwi_regwin_count); ++i) { | |
6816 | if (bwi_regwin_count[i].bbp_id == bbp_id) { | 6816 | if (bwi_regwin_count[i].bbp_id == bbp_id) { | |
6817 | nregwin = bwi_regwin_count[i].nregwin; | 6817 | nregwin = bwi_regwin_count[i].nregwin; | |
6818 | break; | 6818 | break; | |
6819 | } | 6819 | } | |
6820 | } | 6820 | } | |
6821 | if (nregwin == 0) { | 6821 | if (nregwin == 0) { | |
6822 | aprint_error_dev(sc->sc_dev, "no number of win for" | 6822 | aprint_error_dev(sc->sc_dev, "no number of win for" | |
6823 | " BBP id 0x%04x\n", bbp_id); | 6823 | " BBP id 0x%04x\n", bbp_id); | |
6824 | return (ENXIO); | 6824 | return (ENXIO); | |
6825 | } | 6825 | } | |
6826 | } | 6826 | } | |
6827 | 6827 | |||
6828 | /* Record BBP id/rev for later using */ | 6828 | /* Record BBP id/rev for later using */ | |
6829 | sc->sc_bbp_id = bbp_id; | 6829 | sc->sc_bbp_id = bbp_id; | |
6830 | sc->sc_bbp_rev = __SHIFTOUT(info, BWI_INFO_BBPREV_MASK); | 6830 | sc->sc_bbp_rev = __SHIFTOUT(info, BWI_INFO_BBPREV_MASK); | |
6831 | sc->sc_bbp_pkg = __SHIFTOUT(info, BWI_INFO_BBPPKG_MASK); | 6831 | sc->sc_bbp_pkg = __SHIFTOUT(info, BWI_INFO_BBPPKG_MASK); | |
6832 | aprint_normal_dev(sc->sc_dev, | 6832 | aprint_normal_dev(sc->sc_dev, | |
6833 | "BBP id 0x%04x, BBP rev 0x%x, BBP pkg %d\n", | 6833 | "BBP id 0x%04x, BBP rev 0x%x, BBP pkg %d\n", | |
6834 | sc->sc_bbp_id, sc->sc_bbp_rev, sc->sc_bbp_pkg); | 6834 | sc->sc_bbp_id, sc->sc_bbp_rev, sc->sc_bbp_pkg); | |
6835 | DPRINTF(sc, BWI_DBG_ATTACH, "nregwin %d, cap 0x%08x\n", | 6835 | DPRINTF(sc, BWI_DBG_ATTACH, "nregwin %d, cap 0x%08x\n", | |
6836 | nregwin, sc->sc_cap); | 6836 | nregwin, sc->sc_cap); | |
6837 | 6837 | |||
6838 | /* | 6838 | /* | |
6839 | * Create rest of the regwins | 6839 | * Create rest of the regwins | |
6840 | */ | 6840 | */ | |
6841 | 6841 | |||
6842 | /* Don't re-create common regwin, if it is already created */ | 6842 | /* Don't re-create common regwin, if it is already created */ | |
6843 | i = BWI_REGWIN_EXIST(&sc->sc_com_regwin) ? 1 : 0; | 6843 | i = BWI_REGWIN_EXIST(&sc->sc_com_regwin) ? 1 : 0; | |
6844 | 6844 | |||
6845 | for (; i < nregwin; ++i) { | 6845 | for (; i < nregwin; ++i) { | |
6846 | /* | 6846 | /* | |
6847 | * Get regwin information | 6847 | * Get regwin information | |
6848 | */ | 6848 | */ | |
6849 | error = bwi_regwin_select(sc, i); | 6849 | error = bwi_regwin_select(sc, i); | |
6850 | if (error) { | 6850 | if (error) { | |
6851 | aprint_error_dev(sc->sc_dev, "can't select regwin" | 6851 | aprint_error_dev(sc->sc_dev, "can't select regwin" | |
6852 | " %d\n", i); | 6852 | " %d\n", i); | |
6853 | return (error); | 6853 | return (error); | |
6854 | } | 6854 | } | |
6855 | bwi_regwin_info(sc, &rw_type, &rw_rev); | 6855 | bwi_regwin_info(sc, &rw_type, &rw_rev); | |
6856 | 6856 | |||
6857 | /* | 6857 | /* | |
6858 | * Try attach: | 6858 | * Try attach: | |
6859 | * 1) Bus (PCI/PCIE) regwin | 6859 | * 1) Bus (PCI/PCIE) regwin | |
6860 | * 2) MAC regwin | 6860 | * 2) MAC regwin | |
6861 | * Ignore rest types of regwin | 6861 | * Ignore rest types of regwin | |
6862 | */ | 6862 | */ | |
6863 | if (rw_type == BWI_REGWIN_T_BUSPCI || | 6863 | if (rw_type == BWI_REGWIN_T_BUSPCI || | |
6864 | rw_type == BWI_REGWIN_T_BUSPCIE) { | 6864 | rw_type == BWI_REGWIN_T_BUSPCIE) { | |
6865 | if (BWI_REGWIN_EXIST(&sc->sc_bus_regwin)) { | 6865 | if (BWI_REGWIN_EXIST(&sc->sc_bus_regwin)) { | |
6866 | aprint_error_dev(sc->sc_dev, | 6866 | aprint_error_dev(sc->sc_dev, | |
6867 | "bus regwin already exists\n"); | 6867 | "bus regwin already exists\n"); | |
6868 | } else { | 6868 | } else { | |
6869 | BWI_CREATE_REGWIN(&sc->sc_bus_regwin, i, | 6869 | BWI_CREATE_REGWIN(&sc->sc_bus_regwin, i, | |
6870 | rw_type, rw_rev); | 6870 | rw_type, rw_rev); | |
6871 | } | 6871 | } | |
6872 | } else if (rw_type == BWI_REGWIN_T_MAC) { | 6872 | } else if (rw_type == BWI_REGWIN_T_MAC) { | |
6873 | /* XXX ignore return value */ | 6873 | /* XXX ignore return value */ | |
6874 | bwi_mac_attach(sc, i, rw_rev); | 6874 | bwi_mac_attach(sc, i, rw_rev); | |
6875 | } | 6875 | } | |
6876 | } | 6876 | } | |
6877 | 6877 | |||
6878 | /* At least one MAC shold exist */ | 6878 | /* At least one MAC shold exist */ | |
6879 | if (!BWI_REGWIN_EXIST(&sc->sc_mac[0].mac_regwin)) { | 6879 | if (!BWI_REGWIN_EXIST(&sc->sc_mac[0].mac_regwin)) { | |
6880 | aprint_error_dev(sc->sc_dev, "no MAC was found\n"); | 6880 | aprint_error_dev(sc->sc_dev, "no MAC was found\n"); | |
6881 | return (ENXIO); | 6881 | return (ENXIO); | |
6882 | } | 6882 | } | |
6883 | KASSERT(sc->sc_nmac > 0); | 6883 | KASSERT(sc->sc_nmac > 0); | |
6884 | 6884 | |||
6885 | /* Bus regwin must exist */ | 6885 | /* Bus regwin must exist */ | |
6886 | if (!BWI_REGWIN_EXIST(&sc->sc_bus_regwin)) { | 6886 | if (!BWI_REGWIN_EXIST(&sc->sc_bus_regwin)) { | |
6887 | aprint_error_dev(sc->sc_dev, "no bus regwin was found\n"); | 6887 | aprint_error_dev(sc->sc_dev, "no bus regwin was found\n"); | |
6888 | return (ENXIO); | 6888 | return (ENXIO); | |
6889 | } | 6889 | } | |
6890 | 6890 | |||
6891 | /* Start with first MAC */ | 6891 | /* Start with first MAC */ | |
6892 | error = bwi_regwin_switch(sc, &sc->sc_mac[0].mac_regwin, NULL); | 6892 | error = bwi_regwin_switch(sc, &sc->sc_mac[0].mac_regwin, NULL); | |
6893 | if (error) | 6893 | if (error) | |
6894 | return (error); | 6894 | return (error); | |
6895 | 6895 | |||
6896 | return (0); | 6896 | return (0); | |
6897 | } | 6897 | } | |
6898 | 6898 | |||
6899 | static int | 6899 | static int | |
6900 | bwi_bus_init(struct bwi_softc *sc, struct bwi_mac *mac) | 6900 | bwi_bus_init(struct bwi_softc *sc, struct bwi_mac *mac) | |
6901 | { | 6901 | { | |
6902 | struct bwi_regwin *old, *bus; | 6902 | struct bwi_regwin *old, *bus; | |
6903 | uint32_t val; | 6903 | uint32_t val; | |
6904 | int error; | 6904 | int error; | |
6905 | 6905 | |||
6906 | bus = &sc->sc_bus_regwin; | 6906 | bus = &sc->sc_bus_regwin; | |
6907 | KASSERT(sc->sc_cur_regwin == &mac->mac_regwin); | 6907 | KASSERT(sc->sc_cur_regwin == &mac->mac_regwin); | |
6908 | 6908 | |||
6909 | /* | 6909 | /* | |
6910 | * Tell bus to generate requested interrupts | 6910 | * Tell bus to generate requested interrupts | |
6911 | */ | 6911 | */ | |
6912 | if (bus->rw_rev < 6 && bus->rw_type == BWI_REGWIN_T_BUSPCI) { | 6912 | if (bus->rw_rev < 6 && bus->rw_type == BWI_REGWIN_T_BUSPCI) { | |
6913 | /* | 6913 | /* | |
6914 | * NOTE: Read BWI_FLAGS from MAC regwin | 6914 | * NOTE: Read BWI_FLAGS from MAC regwin | |
6915 | */ | 6915 | */ | |
6916 | val = CSR_READ_4(sc, BWI_FLAGS); | 6916 | val = CSR_READ_4(sc, BWI_FLAGS); | |
6917 | 6917 | |||
6918 | error = bwi_regwin_switch(sc, bus, &old); | 6918 | error = bwi_regwin_switch(sc, bus, &old); | |
6919 | if (error) | 6919 | if (error) | |
6920 | return (error); | 6920 | return (error); | |
6921 | 6921 | |||
6922 | CSR_SETBITS_4(sc, BWI_INTRVEC, (val & BWI_FLAGS_INTR_MASK)); | 6922 | CSR_SETBITS_4(sc, BWI_INTRVEC, (val & BWI_FLAGS_INTR_MASK)); | |
6923 | } else { | 6923 | } else { | |
6924 | uint32_t mac_mask; | 6924 | uint32_t mac_mask; | |
6925 | 6925 | |||
6926 | mac_mask = 1 << mac->mac_id; | 6926 | mac_mask = 1 << mac->mac_id; | |
6927 | 6927 | |||
6928 | error = bwi_regwin_switch(sc, bus, &old); | 6928 | error = bwi_regwin_switch(sc, bus, &old); | |
6929 | if (error) | 6929 | if (error) | |
6930 | return (error); | 6930 | return (error); | |
6931 | 6931 | |||
6932 | val = (sc->sc_conf_read)(sc, BWI_PCIR_INTCTL); | 6932 | val = (sc->sc_conf_read)(sc, BWI_PCIR_INTCTL); | |
6933 | val |= mac_mask << 8; | 6933 | val |= mac_mask << 8; | |
6934 | (sc->sc_conf_write)(sc, BWI_PCIR_INTCTL, val); | 6934 | (sc->sc_conf_write)(sc, BWI_PCIR_INTCTL, val); | |
6935 | } | 6935 | } | |
6936 | 6936 | |||
6937 | if (sc->sc_flags & BWI_F_BUS_INITED) | 6937 | if (sc->sc_flags & BWI_F_BUS_INITED) | |
6938 | goto back; | 6938 | goto back; | |
6939 | 6939 | |||
6940 | if (bus->rw_type == BWI_REGWIN_T_BUSPCI) { | 6940 | if (bus->rw_type == BWI_REGWIN_T_BUSPCI) { | |
6941 | /* | 6941 | /* | |
6942 | * Enable prefetch and burst | 6942 | * Enable prefetch and burst | |
6943 | */ | 6943 | */ | |
6944 | CSR_SETBITS_4(sc, BWI_BUS_CONFIG, | 6944 | CSR_SETBITS_4(sc, BWI_BUS_CONFIG, | |
6945 | BWI_BUS_CONFIG_PREFETCH | BWI_BUS_CONFIG_BURST); | 6945 | BWI_BUS_CONFIG_PREFETCH | BWI_BUS_CONFIG_BURST); | |
6946 | 6946 | |||
6947 | if (bus->rw_rev < 5) { | 6947 | if (bus->rw_rev < 5) { | |
6948 | struct bwi_regwin *com = &sc->sc_com_regwin; | 6948 | struct bwi_regwin *com = &sc->sc_com_regwin; | |
6949 | 6949 | |||
6950 | /* | 6950 | /* | |
6951 | * Configure timeouts for bus operation | 6951 | * Configure timeouts for bus operation | |
6952 | */ | 6952 | */ | |
6953 | 6953 | |||
6954 | /* | 6954 | /* | |
6955 | * Set service timeout and request timeout | 6955 | * Set service timeout and request timeout | |
6956 | */ | 6956 | */ | |
6957 | CSR_SETBITS_4(sc, BWI_CONF_LO, | 6957 | CSR_SETBITS_4(sc, BWI_CONF_LO, | |
6958 | __SHIFTIN(BWI_CONF_LO_SERVTO, | 6958 | __SHIFTIN(BWI_CONF_LO_SERVTO, | |
6959 | BWI_CONF_LO_SERVTO_MASK) | | 6959 | BWI_CONF_LO_SERVTO_MASK) | | |
6960 | __SHIFTIN(BWI_CONF_LO_REQTO, | 6960 | __SHIFTIN(BWI_CONF_LO_REQTO, | |
6961 | BWI_CONF_LO_REQTO_MASK)); | 6961 | BWI_CONF_LO_REQTO_MASK)); | |
6962 | 6962 | |||
6963 | /* | 6963 | /* | |
6964 | * If there is common regwin, we switch to that regwin | 6964 | * If there is common regwin, we switch to that regwin | |
6965 | * and switch back to bus regwin once we have done. | 6965 | * and switch back to bus regwin once we have done. | |
6966 | */ | 6966 | */ | |
6967 | if (BWI_REGWIN_EXIST(com)) { | 6967 | if (BWI_REGWIN_EXIST(com)) { | |
6968 | error = bwi_regwin_switch(sc, com, NULL); | 6968 | error = bwi_regwin_switch(sc, com, NULL); | |
6969 | if (error) | 6969 | if (error) | |
6970 | return (error); | 6970 | return (error); | |
6971 | } | 6971 | } | |
6972 | 6972 | |||
6973 | /* Let bus know what we have changed */ | 6973 | /* Let bus know what we have changed */ | |
6974 | CSR_WRITE_4(sc, BWI_BUS_ADDR, BWI_BUS_ADDR_MAGIC); | 6974 | CSR_WRITE_4(sc, BWI_BUS_ADDR, BWI_BUS_ADDR_MAGIC); | |
6975 | CSR_READ_4(sc, BWI_BUS_ADDR); /* Flush */ | 6975 | CSR_READ_4(sc, BWI_BUS_ADDR); /* Flush */ | |
6976 | CSR_WRITE_4(sc, BWI_BUS_DATA, 0); | 6976 | CSR_WRITE_4(sc, BWI_BUS_DATA, 0); | |
6977 | CSR_READ_4(sc, BWI_BUS_DATA); /* Flush */ | 6977 | CSR_READ_4(sc, BWI_BUS_DATA); /* Flush */ | |
6978 | 6978 | |||
6979 | if (BWI_REGWIN_EXIST(com)) { | 6979 | if (BWI_REGWIN_EXIST(com)) { | |
6980 | error = bwi_regwin_switch(sc, bus, NULL); | 6980 | error = bwi_regwin_switch(sc, bus, NULL); | |
6981 | if (error) | 6981 | if (error) | |
6982 | return (error); | 6982 | return (error); | |
6983 | } | 6983 | } | |
6984 | } else if (bus->rw_rev >= 11) { | 6984 | } else if (bus->rw_rev >= 11) { | |
6985 | /* | 6985 | /* | |
6986 | * Enable memory read multiple | 6986 | * Enable memory read multiple | |
6987 | */ | 6987 | */ | |
6988 | CSR_SETBITS_4(sc, BWI_BUS_CONFIG, BWI_BUS_CONFIG_MRM); | 6988 | CSR_SETBITS_4(sc, BWI_BUS_CONFIG, BWI_BUS_CONFIG_MRM); | |
6989 | } | 6989 | } | |
6990 | } else { | 6990 | } else { | |
6991 | /* TODO: PCIE */ | 6991 | /* TODO: PCIE */ | |
6992 | } | 6992 | } | |
6993 | 6993 | |||
6994 | sc->sc_flags |= BWI_F_BUS_INITED; | 6994 | sc->sc_flags |= BWI_F_BUS_INITED; | |
6995 | back: | 6995 | back: | |
6996 | return (bwi_regwin_switch(sc, old, NULL)); | 6996 | return (bwi_regwin_switch(sc, old, NULL)); | |
6997 | } | 6997 | } | |
6998 | 6998 | |||
6999 | static void | 6999 | static void | |
7000 | bwi_get_card_flags(struct bwi_softc *sc) | 7000 | bwi_get_card_flags(struct bwi_softc *sc) | |
7001 | { | 7001 | { | |
7002 | sc->sc_card_flags = bwi_read_sprom(sc, BWI_SPROM_CARD_FLAGS); | 7002 | sc->sc_card_flags = bwi_read_sprom(sc, BWI_SPROM_CARD_FLAGS); | |
7003 | if (sc->sc_card_flags == 0xffff) | 7003 | if (sc->sc_card_flags == 0xffff) | |
7004 | sc->sc_card_flags = 0; | 7004 | sc->sc_card_flags = 0; | |
7005 | 7005 | |||
7006 | if (sc->sc_pci_subvid == PCI_VENDOR_APPLE && | 7006 | if (sc->sc_pci_subvid == PCI_VENDOR_APPLE && | |
7007 | sc->sc_pci_subdid == 0x4e && /* XXX */ | 7007 | sc->sc_pci_subdid == 0x4e && /* XXX */ | |
7008 | sc->sc_pci_revid > 0x40) | 7008 | sc->sc_pci_revid > 0x40) | |
7009 | sc->sc_card_flags |= BWI_CARD_F_PA_GPIO9; | 7009 | sc->sc_card_flags |= BWI_CARD_F_PA_GPIO9; | |
7010 | 7010 | |||
7011 | DPRINTF(sc, BWI_DBG_ATTACH, "card flags 0x%04x\n", sc->sc_card_flags); | 7011 | DPRINTF(sc, BWI_DBG_ATTACH, "card flags 0x%04x\n", sc->sc_card_flags); | |
7012 | } | 7012 | } | |
7013 | 7013 | |||
7014 | static void | 7014 | static void | |
7015 | bwi_get_eaddr(struct bwi_softc *sc, uint16_t eaddr_ofs, uint8_t *eaddr) | 7015 | bwi_get_eaddr(struct bwi_softc *sc, uint16_t eaddr_ofs, uint8_t *eaddr) | |
7016 | { | 7016 | { | |
7017 | int i; | 7017 | int i; | |
7018 | 7018 | |||
7019 | for (i = 0; i < 3; ++i) { | 7019 | for (i = 0; i < 3; ++i) { | |
7020 | *((uint16_t *)eaddr + i) = | 7020 | *((uint16_t *)eaddr + i) = | |
7021 | htobe16(bwi_read_sprom(sc, eaddr_ofs + 2 * i)); | 7021 | htobe16(bwi_read_sprom(sc, eaddr_ofs + 2 * i)); | |
7022 | } | 7022 | } | |
7023 | } | 7023 | } | |
7024 | 7024 | |||
7025 | static void | 7025 | static void | |
7026 | bwi_get_clock_freq(struct bwi_softc *sc, struct bwi_clock_freq *freq) | 7026 | bwi_get_clock_freq(struct bwi_softc *sc, struct bwi_clock_freq *freq) | |
7027 | { | 7027 | { | |
7028 | struct bwi_regwin *com; | 7028 | struct bwi_regwin *com; | |
7029 | uint32_t val; | 7029 | uint32_t val; | |
7030 | uint div; | 7030 | uint div; | |
7031 | int src; | 7031 | int src; | |
7032 | 7032 | |||
7033 | memset(freq, 0, sizeof(*freq)); | 7033 | memset(freq, 0, sizeof(*freq)); | |
7034 | com = &sc->sc_com_regwin; | 7034 | com = &sc->sc_com_regwin; | |
7035 | 7035 | |||
7036 | KASSERT(BWI_REGWIN_EXIST(com)); | 7036 | KASSERT(BWI_REGWIN_EXIST(com)); | |
7037 | KASSERT(sc->sc_cur_regwin == com); | 7037 | KASSERT(sc->sc_cur_regwin == com); | |
7038 | KASSERT(sc->sc_cap & BWI_CAP_CLKMODE); | 7038 | KASSERT(sc->sc_cap & BWI_CAP_CLKMODE); | |
7039 | 7039 | |||
7040 | /* | 7040 | /* | |
7041 | * Calculate clock frequency | 7041 | * Calculate clock frequency | |
7042 | */ | 7042 | */ | |
7043 | src = -1; | 7043 | src = -1; | |
7044 | div = 0; | 7044 | div = 0; | |
7045 | if (com->rw_rev < 6) { | 7045 | if (com->rw_rev < 6) { | |
7046 | val = (sc->sc_conf_read)(sc, BWI_PCIR_GPIO_OUT); | 7046 | val = (sc->sc_conf_read)(sc, BWI_PCIR_GPIO_OUT); | |
7047 | if (val & BWI_PCIM_GPIO_OUT_CLKSRC) { | 7047 | if (val & BWI_PCIM_GPIO_OUT_CLKSRC) { | |
7048 | src = BWI_CLKSRC_PCI; | 7048 | src = BWI_CLKSRC_PCI; | |
7049 | div = 64; | 7049 | div = 64; | |
7050 | } else { | 7050 | } else { | |
7051 | src = BWI_CLKSRC_CS_OSC; | 7051 | src = BWI_CLKSRC_CS_OSC; | |
7052 | div = 32; | 7052 | div = 32; | |
7053 | } | 7053 | } | |
7054 | } else if (com->rw_rev < 10) { | 7054 | } else if (com->rw_rev < 10) { | |
7055 | val = CSR_READ_4(sc, BWI_CLOCK_CTRL); | 7055 | val = CSR_READ_4(sc, BWI_CLOCK_CTRL); | |
7056 | 7056 | |||
7057 | src = __SHIFTOUT(val, BWI_CLOCK_CTRL_CLKSRC); | 7057 | src = __SHIFTOUT(val, BWI_CLOCK_CTRL_CLKSRC); | |
7058 | if (src == BWI_CLKSRC_LP_OSC) | 7058 | if (src == BWI_CLKSRC_LP_OSC) | |
7059 | div = 1; | 7059 | div = 1; | |
7060 | else { | 7060 | else { | |
7061 | div = (__SHIFTOUT(val, BWI_CLOCK_CTRL_FDIV) + 1) << 2; | 7061 | div = (__SHIFTOUT(val, BWI_CLOCK_CTRL_FDIV) + 1) << 2; | |
7062 | 7062 | |||
7063 | /* Unknown source */ | 7063 | /* Unknown source */ | |
7064 | if (src >= BWI_CLKSRC_MAX) | 7064 | if (src >= BWI_CLKSRC_MAX) | |
7065 | src = BWI_CLKSRC_CS_OSC; | 7065 | src = BWI_CLKSRC_CS_OSC; | |
7066 | } | 7066 | } | |
7067 | } else { | 7067 | } else { | |
7068 | val = CSR_READ_4(sc, BWI_CLOCK_INFO); | 7068 | val = CSR_READ_4(sc, BWI_CLOCK_INFO); | |
7069 | 7069 | |||
7070 | src = BWI_CLKSRC_CS_OSC; | 7070 | src = BWI_CLKSRC_CS_OSC; | |
7071 | div = (__SHIFTOUT(val, BWI_CLOCK_INFO_FDIV) + 1) << 2; | 7071 | div = (__SHIFTOUT(val, BWI_CLOCK_INFO_FDIV) + 1) << 2; | |
7072 | } | 7072 | } | |
7073 | 7073 | |||
7074 | KASSERT(src >= 0 && src < BWI_CLKSRC_MAX); | 7074 | KASSERT(src >= 0 && src < BWI_CLKSRC_MAX); | |
7075 | KASSERT(div != 0); | 7075 | KASSERT(div != 0); | |
7076 | 7076 | |||
7077 | DPRINTF(sc, BWI_DBG_ATTACH, "clksrc %s\n", | 7077 | DPRINTF(sc, BWI_DBG_ATTACH, "clksrc %s\n", | |
7078 | src == BWI_CLKSRC_PCI ? "PCI" : | 7078 | src == BWI_CLKSRC_PCI ? "PCI" : | |
7079 | (src == BWI_CLKSRC_LP_OSC ? "LP_OSC" : "CS_OSC")); | 7079 | (src == BWI_CLKSRC_LP_OSC ? "LP_OSC" : "CS_OSC")); | |
7080 | 7080 | |||
7081 | freq->clkfreq_min = bwi_clkfreq[src].freq_min / div; | 7081 | freq->clkfreq_min = bwi_clkfreq[src].freq_min / div; | |
7082 | freq->clkfreq_max = bwi_clkfreq[src].freq_max / div; | 7082 | freq->clkfreq_max = bwi_clkfreq[src].freq_max / div; | |
7083 | 7083 | |||
7084 | DPRINTF(sc, BWI_DBG_ATTACH, "clkfreq min %u, max %u\n", | 7084 | DPRINTF(sc, BWI_DBG_ATTACH, "clkfreq min %u, max %u\n", | |
7085 | freq->clkfreq_min, freq->clkfreq_max); | 7085 | freq->clkfreq_min, freq->clkfreq_max); | |
7086 | } | 7086 | } | |
7087 | 7087 | |||
7088 | static int | 7088 | static int | |
7089 | bwi_set_clock_mode(struct bwi_softc *sc, enum bwi_clock_mode clk_mode) | 7089 | bwi_set_clock_mode(struct bwi_softc *sc, enum bwi_clock_mode clk_mode) | |
7090 | { | 7090 | { | |
7091 | struct bwi_regwin *old, *com; | 7091 | struct bwi_regwin *old, *com; | |
7092 | uint32_t clk_ctrl, clk_src; | 7092 | uint32_t clk_ctrl, clk_src; | |
7093 | int error, pwr_off = 0; | 7093 | int error, pwr_off = 0; | |
7094 | 7094 | |||
7095 | com = &sc->sc_com_regwin; | 7095 | com = &sc->sc_com_regwin; | |
7096 | if (!BWI_REGWIN_EXIST(com)) | 7096 | if (!BWI_REGWIN_EXIST(com)) | |
7097 | return (0); | 7097 | return (0); | |
7098 | 7098 | |||
7099 | if (com->rw_rev >= 10 || com->rw_rev < 6) | 7099 | if (com->rw_rev >= 10 || com->rw_rev < 6) | |
7100 | return (0); | 7100 | return (0); | |
7101 | 7101 | |||
7102 | /* | 7102 | /* | |
7103 | * For common regwin whose rev is [6, 10), the chip | 7103 | * For common regwin whose rev is [6, 10), the chip | |
7104 | * must be capable to change clock mode. | 7104 | * must be capable to change clock mode. | |
7105 | */ | 7105 | */ | |
7106 | if ((sc->sc_cap & BWI_CAP_CLKMODE) == 0) | 7106 | if ((sc->sc_cap & BWI_CAP_CLKMODE) == 0) | |
7107 | return (0); | 7107 | return (0); | |
7108 | 7108 | |||
7109 | error = bwi_regwin_switch(sc, com, &old); | 7109 | error = bwi_regwin_switch(sc, com, &old); | |
7110 | if (error) | 7110 | if (error) | |
7111 | return (error); | 7111 | return (error); | |
7112 | 7112 | |||
7113 | if (clk_mode == BWI_CLOCK_MODE_FAST) | 7113 | if (clk_mode == BWI_CLOCK_MODE_FAST) | |
7114 | bwi_power_on(sc, 0); /* Don't turn on PLL */ | 7114 | bwi_power_on(sc, 0); /* Don't turn on PLL */ | |
7115 | 7115 | |||
7116 | clk_ctrl = CSR_READ_4(sc, BWI_CLOCK_CTRL); | 7116 | clk_ctrl = CSR_READ_4(sc, BWI_CLOCK_CTRL); | |
7117 | clk_src = __SHIFTOUT(clk_ctrl, BWI_CLOCK_CTRL_CLKSRC); | 7117 | clk_src = __SHIFTOUT(clk_ctrl, BWI_CLOCK_CTRL_CLKSRC); | |
7118 | 7118 | |||
7119 | switch (clk_mode) { | 7119 | switch (clk_mode) { | |
7120 | case BWI_CLOCK_MODE_FAST: | 7120 | case BWI_CLOCK_MODE_FAST: | |
7121 | clk_ctrl &= ~BWI_CLOCK_CTRL_SLOW; | 7121 | clk_ctrl &= ~BWI_CLOCK_CTRL_SLOW; | |
7122 | clk_ctrl |= BWI_CLOCK_CTRL_IGNPLL; | 7122 | clk_ctrl |= BWI_CLOCK_CTRL_IGNPLL; | |
7123 | break; | 7123 | break; | |
7124 | case BWI_CLOCK_MODE_SLOW: | 7124 | case BWI_CLOCK_MODE_SLOW: | |
7125 | clk_ctrl |= BWI_CLOCK_CTRL_SLOW; | 7125 | clk_ctrl |= BWI_CLOCK_CTRL_SLOW; | |
7126 | break; | 7126 | break; | |
7127 | case BWI_CLOCK_MODE_DYN: | 7127 | case BWI_CLOCK_MODE_DYN: | |
7128 | clk_ctrl &= ~(BWI_CLOCK_CTRL_SLOW | | 7128 | clk_ctrl &= ~(BWI_CLOCK_CTRL_SLOW | | |
7129 | BWI_CLOCK_CTRL_IGNPLL | | 7129 | BWI_CLOCK_CTRL_IGNPLL | | |
7130 | BWI_CLOCK_CTRL_NODYN); | 7130 | BWI_CLOCK_CTRL_NODYN); | |
7131 | if (clk_src != BWI_CLKSRC_CS_OSC) { | 7131 | if (clk_src != BWI_CLKSRC_CS_OSC) { | |
7132 | clk_ctrl |= BWI_CLOCK_CTRL_NODYN; | 7132 | clk_ctrl |= BWI_CLOCK_CTRL_NODYN; | |
7133 | pwr_off = 1; | 7133 | pwr_off = 1; | |
7134 | } | 7134 | } | |
7135 | break; | 7135 | break; | |
7136 | } | 7136 | } | |
7137 | CSR_WRITE_4(sc, BWI_CLOCK_CTRL, clk_ctrl); | 7137 | CSR_WRITE_4(sc, BWI_CLOCK_CTRL, clk_ctrl); | |
7138 | 7138 | |||
7139 | if (pwr_off) | 7139 | if (pwr_off) | |
7140 | bwi_power_off(sc, 0); /* Leave PLL as it is */ | 7140 | bwi_power_off(sc, 0); /* Leave PLL as it is */ | |
7141 | 7141 | |||
7142 | return (bwi_regwin_switch(sc, old, NULL)); | 7142 | return (bwi_regwin_switch(sc, old, NULL)); | |
7143 | } | 7143 | } | |
7144 | 7144 | |||
7145 | static int | 7145 | static int | |
7146 | bwi_set_clock_delay(struct bwi_softc *sc) | 7146 | bwi_set_clock_delay(struct bwi_softc *sc) | |
7147 | { | 7147 | { | |
7148 | struct bwi_regwin *old, *com; | 7148 | struct bwi_regwin *old, *com; | |
7149 | int error; | 7149 | int error; | |
7150 | 7150 | |||
7151 | com = &sc->sc_com_regwin; | 7151 | com = &sc->sc_com_regwin; | |
7152 | if (!BWI_REGWIN_EXIST(com)) | 7152 | if (!BWI_REGWIN_EXIST(com)) | |
7153 | return (0); | 7153 | return (0); | |
7154 | 7154 | |||
7155 | error = bwi_regwin_switch(sc, com, &old); | 7155 | error = bwi_regwin_switch(sc, com, &old); | |
7156 | if (error) | 7156 | if (error) | |
7157 | return (error); | 7157 | return (error); | |
7158 | 7158 | |||
7159 | if (sc->sc_bbp_id == BWI_BBPID_BCM4321) { | 7159 | if (sc->sc_bbp_id == BWI_BBPID_BCM4321) { | |
7160 | if (sc->sc_bbp_rev == 0) | 7160 | if (sc->sc_bbp_rev == 0) | |
7161 | CSR_WRITE_4(sc, BWI_CONTROL, BWI_CONTROL_MAGIC0); | 7161 | CSR_WRITE_4(sc, BWI_CONTROL, BWI_CONTROL_MAGIC0); | |
7162 | else if (sc->sc_bbp_rev == 1) | 7162 | else if (sc->sc_bbp_rev == 1) | |
7163 | CSR_WRITE_4(sc, BWI_CONTROL, BWI_CONTROL_MAGIC1); | 7163 | CSR_WRITE_4(sc, BWI_CONTROL, BWI_CONTROL_MAGIC1); | |
7164 | } | 7164 | } | |
7165 | 7165 | |||
7166 | if (sc->sc_cap & BWI_CAP_CLKMODE) { | 7166 | if (sc->sc_cap & BWI_CAP_CLKMODE) { | |
7167 | if (com->rw_rev >= 10) | 7167 | if (com->rw_rev >= 10) | |
7168 | CSR_FILT_SETBITS_4(sc, BWI_CLOCK_INFO, 0xffff, 0x40000); | 7168 | CSR_FILT_SETBITS_4(sc, BWI_CLOCK_INFO, 0xffff, 0x40000); | |
7169 | else { | 7169 | else { | |
7170 | struct bwi_clock_freq freq; | 7170 | struct bwi_clock_freq freq; | |
7171 | 7171 | |||
7172 | bwi_get_clock_freq(sc, &freq); | 7172 | bwi_get_clock_freq(sc, &freq); | |
7173 | CSR_WRITE_4(sc, BWI_PLL_ON_DELAY, | 7173 | CSR_WRITE_4(sc, BWI_PLL_ON_DELAY, | |
7174 | howmany(freq.clkfreq_max * 150, 1000000)); | 7174 | howmany(freq.clkfreq_max * 150, 1000000)); | |
7175 | CSR_WRITE_4(sc, BWI_FREQ_SEL_DELAY, | 7175 | CSR_WRITE_4(sc, BWI_FREQ_SEL_DELAY, | |
7176 | howmany(freq.clkfreq_max * 15, 1000000)); | 7176 | howmany(freq.clkfreq_max * 15, 1000000)); | |
7177 | } | 7177 | } | |
7178 | } | 7178 | } | |
7179 | 7179 | |||
7180 | return (bwi_regwin_switch(sc, old, NULL)); | 7180 | return (bwi_regwin_switch(sc, old, NULL)); | |
7181 | } | 7181 | } | |
7182 | 7182 | |||
7183 | static int | 7183 | static int | |
7184 | bwi_init(struct ifnet *ifp) | 7184 | bwi_init(struct ifnet *ifp) | |
7185 | { | 7185 | { | |
7186 | struct bwi_softc *sc = ifp->if_softc; | 7186 | struct bwi_softc *sc = ifp->if_softc; | |
7187 | 7187 | |||
7188 | bwi_init_statechg(sc, 1); | 7188 | bwi_init_statechg(sc, 1); | |
7189 | 7189 | |||
7190 | return (0); | 7190 | return (0); | |
7191 | } | 7191 | } | |
7192 | 7192 | |||
7193 | static void | 7193 | static void | |
7194 | bwi_init_statechg(struct bwi_softc *sc, int statechg) | 7194 | bwi_init_statechg(struct bwi_softc *sc, int statechg) | |
7195 | { | 7195 | { | |
7196 | struct ieee80211com *ic = &sc->sc_ic; | 7196 | struct ieee80211com *ic = &sc->sc_ic; | |
7197 | struct ifnet *ifp = &sc->sc_if; | 7197 | struct ifnet *ifp = &sc->sc_if; | |
7198 | struct bwi_mac *mac; | 7198 | struct bwi_mac *mac; | |
7199 | int error; | 7199 | int error; | |
7200 | 7200 | |||
7201 | DPRINTF(sc, BWI_DBG_MISC, "%s\n", __func__); | 7201 | DPRINTF(sc, BWI_DBG_MISC, "%s\n", __func__); | |
7202 | 7202 | |||
7203 | bwi_stop(ifp, statechg); | 7203 | bwi_stop(ifp, statechg); | |
7204 | 7204 | |||
7205 | /* power on cardbus socket */ | 7205 | /* power on cardbus socket */ | |
7206 | if (sc->sc_enable != NULL) | 7206 | if (sc->sc_enable != NULL) | |
7207 | (sc->sc_enable)(sc, 0); | 7207 | (sc->sc_enable)(sc, 0); | |
7208 | 7208 | |||
7209 | bwi_bbp_power_on(sc, BWI_CLOCK_MODE_FAST); | 7209 | bwi_bbp_power_on(sc, BWI_CLOCK_MODE_FAST); | |
7210 | 7210 | |||
7211 | /* TODO: 2 MAC */ | 7211 | /* TODO: 2 MAC */ | |
7212 | 7212 | |||
7213 | mac = &sc->sc_mac[0]; | 7213 | mac = &sc->sc_mac[0]; | |
7214 | error = bwi_regwin_switch(sc, &mac->mac_regwin, NULL); | 7214 | error = bwi_regwin_switch(sc, &mac->mac_regwin, NULL); | |
7215 | if (error) | 7215 | if (error) | |
7216 | goto back; | 7216 | goto back; | |
7217 | 7217 | |||
7218 | error = bwi_mac_init(mac); | 7218 | error = bwi_mac_init(mac); | |
7219 | if (error) | 7219 | if (error) | |
7220 | goto back; | 7220 | goto back; | |
7221 | 7221 | |||
7222 | bwi_bbp_power_on(sc, BWI_CLOCK_MODE_DYN); | 7222 | bwi_bbp_power_on(sc, BWI_CLOCK_MODE_DYN); | |
7223 | 7223 | |||
7224 | IEEE80211_ADDR_COPY(ic->ic_myaddr, CLLADDR(ifp->if_sadl)); | 7224 | IEEE80211_ADDR_COPY(ic->ic_myaddr, CLLADDR(ifp->if_sadl)); | |
7225 | 7225 | |||
7226 | bwi_set_bssid(sc, bwi_zero_addr); /* Clear BSSID */ | 7226 | bwi_set_bssid(sc, bwi_zero_addr); /* Clear BSSID */ | |
7227 | bwi_set_addr_filter(sc, BWI_ADDR_FILTER_MYADDR, ic->ic_myaddr); | 7227 | bwi_set_addr_filter(sc, BWI_ADDR_FILTER_MYADDR, ic->ic_myaddr); | |
7228 | 7228 | |||
7229 | bwi_mac_reset_hwkeys(mac); | 7229 | bwi_mac_reset_hwkeys(mac); | |
7230 | 7230 | |||
7231 | if ((mac->mac_flags & BWI_MAC_F_HAS_TXSTATS) == 0) { | 7231 | if ((mac->mac_flags & BWI_MAC_F_HAS_TXSTATS) == 0) { | |
7232 | int i; | 7232 | int i; | |
7233 | 7233 | |||
7234 | #define NRETRY 1000 | 7234 | #define NRETRY 1000 | |
7235 | /* | 7235 | /* | |
7236 | * Drain any possible pending TX status | 7236 | * Drain any possible pending TX status | |
7237 | */ | 7237 | */ | |
7238 | for (i = 0; i < NRETRY; ++i) { | 7238 | for (i = 0; i < NRETRY; ++i) { | |
7239 | if ((CSR_READ_4(sc, BWI_TXSTATUS_0) & | 7239 | if ((CSR_READ_4(sc, BWI_TXSTATUS_0) & | |
7240 | BWI_TXSTATUS_0_MORE) == 0) | 7240 | BWI_TXSTATUS_0_MORE) == 0) | |
7241 | break; | 7241 | break; | |
7242 | CSR_READ_4(sc, BWI_TXSTATUS_1); | 7242 | CSR_READ_4(sc, BWI_TXSTATUS_1); | |
7243 | } | 7243 | } | |
7244 | if (i == NRETRY) | 7244 | if (i == NRETRY) | |
7245 | aprint_error_dev(sc->sc_dev, | 7245 | aprint_error_dev(sc->sc_dev, | |
7246 | "can't drain TX status\n"); | 7246 | "can't drain TX status\n"); | |
7247 | #undef NRETRY | 7247 | #undef NRETRY | |
7248 | } | 7248 | } | |
7249 | 7249 | |||
7250 | if (mac->mac_phy.phy_mode == IEEE80211_MODE_11G) | 7250 | if (mac->mac_phy.phy_mode == IEEE80211_MODE_11G) | |
7251 | bwi_mac_updateslot(mac, 1); | 7251 | bwi_mac_updateslot(mac, 1); | |
7252 | 7252 | |||
7253 | /* Start MAC */ | 7253 | /* Start MAC */ | |
7254 | error = bwi_mac_start(mac); | 7254 | error = bwi_mac_start(mac); | |
7255 | if (error) | 7255 | if (error) | |
7256 | goto back; | 7256 | goto back; | |
7257 | 7257 | |||
7258 | /* Enable intrs */ | 7258 | /* Enable intrs */ | |
7259 | bwi_enable_intrs(sc, BWI_INIT_INTRS); | 7259 | bwi_enable_intrs(sc, BWI_INIT_INTRS); | |
7260 | 7260 | |||
7261 | ifp->if_flags |= IFF_RUNNING; | 7261 | ifp->if_flags |= IFF_RUNNING; | |
7262 | ifp->if_flags &= ~IFF_OACTIVE; | 7262 | ifp->if_flags &= ~IFF_OACTIVE; | |
7263 | 7263 | |||
7264 | if (statechg) { | 7264 | if (statechg) { | |
7265 | if (ic->ic_opmode != IEEE80211_M_MONITOR) { | 7265 | if (ic->ic_opmode != IEEE80211_M_MONITOR) { | |
7266 | /* [TRC: XXX OpenBSD omits this conditional.] */ | 7266 | /* [TRC: XXX OpenBSD omits this conditional.] */ | |
7267 | if (ic->ic_roaming != IEEE80211_ROAMING_MANUAL) | 7267 | if (ic->ic_roaming != IEEE80211_ROAMING_MANUAL) | |
7268 | ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); | 7268 | ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); | |
7269 | } else { | 7269 | } else { | |
7270 | ieee80211_new_state(ic, IEEE80211_S_RUN, -1); | 7270 | ieee80211_new_state(ic, IEEE80211_S_RUN, -1); | |
7271 | } | 7271 | } | |
7272 | } else { | 7272 | } else { | |
7273 | ieee80211_new_state(ic, ic->ic_state, -1); | 7273 | ieee80211_new_state(ic, ic->ic_state, -1); | |
7274 | } | 7274 | } | |
7275 | 7275 | |||
7276 | back: | 7276 | back: | |
7277 | if (error) | 7277 | if (error) | |
7278 | bwi_stop(ifp, 1); | 7278 | bwi_stop(ifp, 1); | |
7279 | else | 7279 | else | |
7280 | /* [TRC: XXX DragonFlyBD uses ifp->if_start(ifp).] */ | 7280 | /* [TRC: XXX DragonFlyBD uses ifp->if_start(ifp).] */ | |
7281 | bwi_start(ifp); | 7281 | bwi_start(ifp); | |
7282 | } | 7282 | } | |
7283 | 7283 | |||
7284 | static int | 7284 | static int | |
7285 | bwi_ioctl(struct ifnet *ifp, u_long cmd, void *data) | 7285 | bwi_ioctl(struct ifnet *ifp, u_long cmd, void *data) | |
7286 | { | 7286 | { | |
7287 | struct bwi_softc *sc = ifp->if_softc; | 7287 | struct bwi_softc *sc = ifp->if_softc; | |
7288 | struct ieee80211com *ic = &sc->sc_ic; | 7288 | struct ieee80211com *ic = &sc->sc_ic; | |
7289 | int s, error = 0; | 7289 | int s, error = 0; | |
7290 | 7290 | |||
7291 | /* [TRC: XXX Superstitiously cargo-culted from wi(4).] */ | 7291 | /* [TRC: XXX Superstitiously cargo-culted from wi(4).] */ | |
7292 | if (!device_is_active(sc->sc_dev)) | 7292 | if (!device_is_active(sc->sc_dev)) | |
7293 | return (ENXIO); | 7293 | return (ENXIO); | |
7294 | 7294 | |||
7295 | s = splnet(); | 7295 | s = splnet(); | |
7296 | 7296 | |||
7297 | switch (cmd) { | 7297 | switch (cmd) { | |
7298 | case SIOCSIFFLAGS: | 7298 | case SIOCSIFFLAGS: | |
7299 | if ((error = ifioctl_common(ifp, cmd, data)) != 0) | 7299 | if ((error = ifioctl_common(ifp, cmd, data)) != 0) | |
7300 | break; | 7300 | break; | |
7301 | if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) == | 7301 | if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) == | |
7302 | (IFF_UP | IFF_RUNNING)) { | 7302 | (IFF_UP | IFF_RUNNING)) { | |
7303 | struct bwi_mac *mac; | 7303 | struct bwi_mac *mac; | |
7304 | int promisc = -1; | 7304 | int promisc = -1; | |
7305 | 7305 | |||
7306 | KASSERT(sc->sc_cur_regwin->rw_type == | 7306 | KASSERT(sc->sc_cur_regwin->rw_type == | |
7307 | BWI_REGWIN_T_MAC); | 7307 | BWI_REGWIN_T_MAC); | |
7308 | mac = (struct bwi_mac *)sc->sc_cur_regwin; | 7308 | mac = (struct bwi_mac *)sc->sc_cur_regwin; | |
7309 | 7309 | |||
7310 | if ((ifp->if_flags & IFF_PROMISC) && | 7310 | if ((ifp->if_flags & IFF_PROMISC) && | |
7311 | (sc->sc_flags & BWI_F_PROMISC) == 0) { | 7311 | (sc->sc_flags & BWI_F_PROMISC) == 0) { | |
7312 | promisc = 1; | 7312 | promisc = 1; | |
7313 | sc->sc_flags |= BWI_F_PROMISC; | 7313 | sc->sc_flags |= BWI_F_PROMISC; | |
7314 | } else if ((ifp->if_flags & IFF_PROMISC) == 0 && | 7314 | } else if ((ifp->if_flags & IFF_PROMISC) == 0 && | |
7315 | (sc->sc_flags & BWI_F_PROMISC)) { | 7315 | (sc->sc_flags & BWI_F_PROMISC)) { | |
7316 | promisc = 0; | 7316 | promisc = 0; | |
7317 | sc->sc_flags &= ~BWI_F_PROMISC; | 7317 | sc->sc_flags &= ~BWI_F_PROMISC; | |
7318 | } | 7318 | } | |
7319 | 7319 | |||
7320 | if (promisc >= 0) | 7320 | if (promisc >= 0) | |
7321 | bwi_mac_set_promisc(mac, promisc); | 7321 | bwi_mac_set_promisc(mac, promisc); | |
7322 | } | 7322 | } | |
7323 | 7323 | |||
7324 | if (ifp->if_flags & IFF_UP) { | 7324 | if (ifp->if_flags & IFF_UP) { | |
7325 | if (!(ifp->if_flags & IFF_RUNNING)) | 7325 | if (!(ifp->if_flags & IFF_RUNNING)) | |
7326 | bwi_init(ifp); | 7326 | bwi_init(ifp); | |
7327 | } else { | 7327 | } else { | |
7328 | if (ifp->if_flags & IFF_RUNNING) | 7328 | if (ifp->if_flags & IFF_RUNNING) | |
7329 | bwi_stop(ifp, 1); | 7329 | bwi_stop(ifp, 1); | |
7330 | } | 7330 | } | |
7331 | break; | 7331 | break; | |
7332 | 7332 | |||
7333 | case SIOCADDMULTI: | 7333 | case SIOCADDMULTI: | |
7334 | case SIOCDELMULTI: | 7334 | case SIOCDELMULTI: | |
7335 | /* [TRC: Several other drivers appear to have this | 7335 | /* [TRC: Several other drivers appear to have this | |
7336 | copied & pasted, so I'm following suit.] */ | 7336 | copied & pasted, so I'm following suit.] */ | |
7337 | /* XXX no h/w multicast filter? --dyoung */ | 7337 | /* XXX no h/w multicast filter? --dyoung */ | |
7338 | if ((error = ether_ioctl(ifp, cmd, data)) == ENETRESET) { | 7338 | if ((error = ether_ioctl(ifp, cmd, data)) == ENETRESET) { | |
7339 | /* setup multicast filter, etc */ | 7339 | /* setup multicast filter, etc */ | |
7340 | error = 0; | 7340 | error = 0; | |
7341 | } | 7341 | } | |
7342 | break; | 7342 | break; | |
7343 | 7343 | |||
7344 | case SIOCS80211CHANNEL: | 7344 | case SIOCS80211CHANNEL: | |
7345 | /* [TRC: Pilfered from OpenBSD. No clue whether it works.] */ | 7345 | /* [TRC: Pilfered from OpenBSD. No clue whether it works.] */ | |
7346 | /* allow fast channel switching in monitor mode */ | 7346 | /* allow fast channel switching in monitor mode */ | |
7347 | error = ieee80211_ioctl(ic, cmd, data); | 7347 | error = ieee80211_ioctl(ic, cmd, data); | |
7348 | if (error == ENETRESET && | 7348 | if (error == ENETRESET && | |
7349 | ic->ic_opmode == IEEE80211_M_MONITOR) { | 7349 | ic->ic_opmode == IEEE80211_M_MONITOR) { | |
7350 | if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) == | 7350 | if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) == | |
7351 | (IFF_UP | IFF_RUNNING)) { | 7351 | (IFF_UP | IFF_RUNNING)) { | |
7352 | /* [TRC: XXX ????] */ | 7352 | /* [TRC: XXX ????] */ | |
7353 | ic->ic_bss->ni_chan = ic->ic_ibss_chan; | 7353 | ic->ic_bss->ni_chan = ic->ic_ibss_chan; | |
7354 | ic->ic_curchan = ic->ic_ibss_chan; | 7354 | ic->ic_curchan = ic->ic_ibss_chan; | |
7355 | bwi_set_chan(sc, ic->ic_bss->ni_chan); | 7355 | bwi_set_chan(sc, ic->ic_bss->ni_chan); | |
7356 | } | 7356 | } | |
7357 | error = 0; | 7357 | error = 0; | |
7358 | } | 7358 | } | |
7359 | break; | 7359 | break; | |
7360 | 7360 | |||
7361 | default: | 7361 | default: | |
7362 | error = ieee80211_ioctl(ic, cmd, data); | 7362 | error = ieee80211_ioctl(ic, cmd, data); | |
7363 | break; | 7363 | break; | |
7364 | } | 7364 | } | |
7365 | 7365 | |||
7366 | if (error == ENETRESET) { | 7366 | if (error == ENETRESET) { | |
7367 | if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) == | 7367 | if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) == | |
7368 | (IFF_UP | IFF_RUNNING) && | 7368 | (IFF_UP | IFF_RUNNING) && | |
7369 | /* [TRC: XXX Superstitiously cargo-culted from iwi(4). */ | 7369 | /* [TRC: XXX Superstitiously cargo-culted from iwi(4). */ | |
7370 | (ic->ic_roaming != IEEE80211_ROAMING_MANUAL)) | 7370 | (ic->ic_roaming != IEEE80211_ROAMING_MANUAL)) | |
7371 | bwi_init(ifp); | 7371 | bwi_init(ifp); | |
7372 | error = 0; | 7372 | error = 0; | |
7373 | } | 7373 | } | |
7374 | 7374 | |||
7375 | splx(s); | 7375 | splx(s); | |
7376 | 7376 | |||
7377 | return (error); | 7377 | return (error); | |
7378 | } | 7378 | } | |
7379 | 7379 | |||
7380 | static void | 7380 | static void | |
7381 | bwi_start(struct ifnet *ifp) | 7381 | bwi_start(struct ifnet *ifp) | |
7382 | { | 7382 | { | |
7383 | struct bwi_softc *sc = ifp->if_softc; | 7383 | struct bwi_softc *sc = ifp->if_softc; | |
7384 | struct ieee80211com *ic = &sc->sc_ic; | 7384 | struct ieee80211com *ic = &sc->sc_ic; | |
7385 | struct bwi_txbuf_data *tbd = &sc->sc_tx_bdata[BWI_TX_DATA_RING]; | 7385 | struct bwi_txbuf_data *tbd = &sc->sc_tx_bdata[BWI_TX_DATA_RING]; | |
7386 | int trans, idx; | 7386 | int trans, idx; | |
7387 | 7387 | |||
7388 | /* [TRC: XXX I'm not sure under which conditions we're actually | 7388 | /* [TRC: XXX I'm not sure under which conditions we're actually | |
7389 | supposed to refuse to start, so I'm copying what OpenBSD and | 7389 | supposed to refuse to start, so I'm copying what OpenBSD and | |
7390 | DragonFlyBSD do, even if no one else on NetBSD does it. */ | 7390 | DragonFlyBSD do, even if no one else on NetBSD does it. */ | |
7391 | if ((ifp->if_flags & IFF_OACTIVE) || | 7391 | if ((ifp->if_flags & IFF_OACTIVE) || | |
7392 | (ifp->if_flags & IFF_RUNNING) == 0) | 7392 | (ifp->if_flags & IFF_RUNNING) == 0) | |
7393 | return; | 7393 | return; | |
7394 | 7394 | |||
7395 | trans = 0; | 7395 | trans = 0; | |
7396 | idx = tbd->tbd_idx; | 7396 | idx = tbd->tbd_idx; | |
7397 | 7397 | |||
7398 | while (tbd->tbd_buf[idx].tb_mbuf == NULL) { | 7398 | while (tbd->tbd_buf[idx].tb_mbuf == NULL) { | |
7399 | struct ieee80211_frame *wh; | 7399 | struct ieee80211_frame *wh; | |
7400 | struct ieee80211_node *ni; | 7400 | struct ieee80211_node *ni; | |
7401 | struct mbuf *m; | 7401 | struct mbuf *m; | |
7402 | int mgt_pkt = 0; | 7402 | int mgt_pkt = 0; | |
7403 | 7403 | |||
7404 | IF_DEQUEUE(&ic->ic_mgtq, m); | 7404 | IF_DEQUEUE(&ic->ic_mgtq, m); | |
7405 | if (m != NULL) { | 7405 | if (m != NULL) { | |
7406 | ni = M_GETCTX(m, struct ieee80211_node *); | 7406 | ni = M_GETCTX(m, struct ieee80211_node *); | |
7407 | M_CLEARCTX(m); | 7407 | M_CLEARCTX(m); | |
7408 | 7408 | |||
7409 | mgt_pkt = 1; | 7409 | mgt_pkt = 1; | |
7410 | } else { | 7410 | } else { | |
7411 | struct ether_header *eh; | 7411 | struct ether_header *eh; | |
7412 | 7412 | |||
7413 | if (ic->ic_state != IEEE80211_S_RUN) | 7413 | if (ic->ic_state != IEEE80211_S_RUN) | |
7414 | break; | 7414 | break; | |
7415 | 7415 | |||
7416 | IFQ_DEQUEUE(&ifp->if_snd, m); | 7416 | IFQ_DEQUEUE(&ifp->if_snd, m); | |
7417 | if (m == NULL) | 7417 | if (m == NULL) | |
7418 | break; | 7418 | break; | |
7419 | 7419 | |||
7420 | if (m->m_len < sizeof(*eh)) { | 7420 | if (m->m_len < sizeof(*eh)) { | |
7421 | m = m_pullup(m, sizeof(*eh)); | 7421 | m = m_pullup(m, sizeof(*eh)); | |
7422 | if (m == NULL) { | 7422 | if (m == NULL) { | |
7423 | ifp->if_oerrors++; | 7423 | if_statinc(ifp, if_oerrors); | |
7424 | continue; | 7424 | continue; | |
7425 | } | 7425 | } | |
7426 | } | 7426 | } | |
7427 | eh = mtod(m, struct ether_header *); | 7427 | eh = mtod(m, struct ether_header *); | |
7428 | 7428 | |||
7429 | ni = ieee80211_find_txnode(ic, eh->ether_dhost); | 7429 | ni = ieee80211_find_txnode(ic, eh->ether_dhost); | |
7430 | if (ni == NULL) { | 7430 | if (ni == NULL) { | |
7431 | ifp->if_oerrors++; | 7431 | if_statinc(ifp, if_oerrors); | |
7432 | m_freem(m); | 7432 | m_freem(m); | |
7433 | continue; | 7433 | continue; | |
7434 | } | 7434 | } | |
7435 | 7435 | |||
7436 | /* [TRC: XXX Superstitiously cargo-culted from | 7436 | /* [TRC: XXX Superstitiously cargo-culted from | |
7437 | ath(4) and wi(4).] */ | 7437 | ath(4) and wi(4).] */ | |
7438 | if ((ni->ni_flags & IEEE80211_NODE_PWR_MGT) && | 7438 | if ((ni->ni_flags & IEEE80211_NODE_PWR_MGT) && | |
7439 | (m->m_flags & M_PWR_SAV) == 0) { | 7439 | (m->m_flags & M_PWR_SAV) == 0) { | |
7440 | ieee80211_pwrsave(ic, ni, m); | 7440 | ieee80211_pwrsave(ic, ni, m); | |
7441 | ieee80211_free_node(ni); | 7441 | ieee80211_free_node(ni); | |
7442 | continue; | 7442 | continue; | |
7443 | } | 7443 | } | |
7444 | 7444 | |||
7445 | /* [TRC: XXX I *think* we're supposed to do | 7445 | /* [TRC: XXX I *think* we're supposed to do | |
7446 | this, but honestly I have no clue. We don't | 7446 | this, but honestly I have no clue. We don't | |
7447 | use M_WME_GETAC, so...] */ | 7447 | use M_WME_GETAC, so...] */ | |
7448 | if (ieee80211_classify(ic, m, ni)) { | 7448 | if (ieee80211_classify(ic, m, ni)) { | |
7449 | /* [TRC: XXX What debug flag?] */ | 7449 | /* [TRC: XXX What debug flag?] */ | |
7450 | DPRINTF(sc, BWI_DBG_MISC, | 7450 | DPRINTF(sc, BWI_DBG_MISC, | |
7451 | "%s: discard, classification failure\n", | 7451 | "%s: discard, classification failure\n", | |
7452 | __func__); | 7452 | __func__); | |
7453 | ifp->if_oerrors++; | 7453 | if_statinc(ifp, if_oerrors); | |
7454 | m_freem(m); | 7454 | m_freem(m); | |
7455 | ieee80211_free_node(ni); | 7455 | ieee80211_free_node(ni); | |
7456 | continue; | 7456 | continue; | |
7457 | } | 7457 | } | |
7458 | 7458 | |||
7459 | /* [TRC: XXX wi(4) and awi(4) do this; iwi(4) | 7459 | /* [TRC: XXX wi(4) and awi(4) do this; iwi(4) | |
7460 | doesn't.] */ | 7460 | doesn't.] */ | |
7461 | ifp->if_opackets++; | 7461 | if_statinc(ifp, if_opackets); | |
7462 | 7462 | |||
7463 | /* [TRC: XXX When should the packet be | 7463 | /* [TRC: XXX When should the packet be | |
7464 | filtered? Different drivers appear to do it | 7464 | filtered? Different drivers appear to do it | |
7465 | at different times.] */ | 7465 | at different times.] */ | |
7466 | /* TODO: PS */ | 7466 | /* TODO: PS */ | |
7467 | bpf_mtap(ifp, m, BPF_D_OUT); | 7467 | bpf_mtap(ifp, m, BPF_D_OUT); | |
7468 | m = ieee80211_encap(ic, m, ni); | 7468 | m = ieee80211_encap(ic, m, ni); | |
7469 | if (m == NULL) { | 7469 | if (m == NULL) { | |
7470 | ifp->if_oerrors++; | 7470 | if_statinc(ifp, if_oerrors); | |
7471 | ieee80211_free_node(ni); | 7471 | ieee80211_free_node(ni); | |
7472 | continue; | 7472 | continue; | |
7473 | } | 7473 | } | |
7474 | } | 7474 | } | |
7475 | bpf_mtap3(ic->ic_rawbpf, m, BPF_D_OUT); | 7475 | bpf_mtap3(ic->ic_rawbpf, m, BPF_D_OUT); | |
7476 | 7476 | |||
7477 | wh = mtod(m, struct ieee80211_frame *); | 7477 | wh = mtod(m, struct ieee80211_frame *); | |
7478 | /* [TRC: XXX What about ic->ic_flags & IEEE80211_F_PRIVACY?] */ | 7478 | /* [TRC: XXX What about ic->ic_flags & IEEE80211_F_PRIVACY?] */ | |
7479 | if (wh->i_fc[1] & IEEE80211_FC1_WEP) { | 7479 | if (wh->i_fc[1] & IEEE80211_FC1_WEP) { | |
7480 | if (ieee80211_crypto_encap(ic, ni, m) == NULL) { | 7480 | if (ieee80211_crypto_encap(ic, ni, m) == NULL) { | |
7481 | ifp->if_oerrors++; | 7481 | if_statinc(ifp, if_oerrors); | |
7482 | m_freem(m); | 7482 | m_freem(m); | |
7483 | ieee80211_free_node(ni); | 7483 | ieee80211_free_node(ni); | |
7484 | continue; | 7484 | continue; | |
7485 | } | 7485 | } | |
7486 | } | 7486 | } | |
7487 | wh = NULL; /* [TRC: XXX Huh?] */ | 7487 | wh = NULL; /* [TRC: XXX Huh?] */ | |
7488 | 7488 | |||
7489 | if (bwi_encap(sc, idx, m, &ni, mgt_pkt) != 0) { | 7489 | if (bwi_encap(sc, idx, m, &ni, mgt_pkt) != 0) { | |
7490 | /* 'm' is freed in bwi_encap() if we reach here */ | 7490 | /* 'm' is freed in bwi_encap() if we reach here */ | |
7491 | ifp->if_oerrors++; | 7491 | if_statinc(ifp, if_oerrors); | |
7492 | if (ni != NULL) | 7492 | if (ni != NULL) | |
7493 | ieee80211_free_node(ni); | 7493 | ieee80211_free_node(ni); | |
7494 | continue; | 7494 | continue; | |
7495 | } | 7495 | } | |
7496 | 7496 | |||
7497 | trans = 1; | 7497 | trans = 1; | |
7498 | tbd->tbd_used++; | 7498 | tbd->tbd_used++; | |
7499 | idx = (idx + 1) % BWI_TX_NDESC; | 7499 | idx = (idx + 1) % BWI_TX_NDESC; | |
7500 | 7500 | |||
7501 | if (tbd->tbd_used + BWI_TX_NSPRDESC >= BWI_TX_NDESC) { | 7501 | if (tbd->tbd_used + BWI_TX_NSPRDESC >= BWI_TX_NDESC) { | |
7502 | ifp->if_flags |= IFF_OACTIVE; | 7502 | ifp->if_flags |= IFF_OACTIVE; | |
7503 | break; | 7503 | break; | |
7504 | } | 7504 | } | |
7505 | } | 7505 | } | |
7506 | tbd->tbd_idx = idx; | 7506 | tbd->tbd_idx = idx; | |
7507 | 7507 | |||
7508 | if (trans) | 7508 | if (trans) | |
7509 | sc->sc_tx_timer = 5; | 7509 | sc->sc_tx_timer = 5; | |
7510 | ifp->if_timer = 1; | 7510 | ifp->if_timer = 1; | |
7511 | } | 7511 | } | |
7512 | 7512 | |||
7513 | static void | 7513 | static void | |
7514 | bwi_watchdog(struct ifnet *ifp) | 7514 | bwi_watchdog(struct ifnet *ifp) | |
7515 | { | 7515 | { | |
7516 | struct bwi_softc *sc = ifp->if_softc; | 7516 | struct bwi_softc *sc = ifp->if_softc; | |
7517 | 7517 | |||
7518 | ifp->if_timer = 0; | 7518 | ifp->if_timer = 0; | |
7519 | 7519 | |||
7520 | if ((ifp->if_flags & IFF_RUNNING) == 0 || | 7520 | if ((ifp->if_flags & IFF_RUNNING) == 0 || | |
7521 | !device_is_active(sc->sc_dev)) | 7521 | !device_is_active(sc->sc_dev)) | |
7522 | return; | 7522 | return; | |
7523 | 7523 | |||
7524 | if (sc->sc_tx_timer) { | 7524 | if (sc->sc_tx_timer) { | |
7525 | if (--sc->sc_tx_timer == 0) { | 7525 | if (--sc->sc_tx_timer == 0) { | |
7526 | aprint_error_dev(sc->sc_dev, "device timeout\n"); | 7526 | aprint_error_dev(sc->sc_dev, "device timeout\n"); | |
7527 | ifp->if_oerrors++; | 7527 | if_statinc(ifp, if_oerrors); | |
7528 | /* TODO */ | 7528 | /* TODO */ | |
7529 | /* [TRC: XXX TODO what? Stop the device? | 7529 | /* [TRC: XXX TODO what? Stop the device? | |
7530 | Bring it down? iwi(4) does this.] */ | 7530 | Bring it down? iwi(4) does this.] */ | |
7531 | } else | 7531 | } else | |
7532 | ifp->if_timer = 1; | 7532 | ifp->if_timer = 1; | |
7533 | } | 7533 | } | |
7534 | 7534 | |||
7535 | ieee80211_watchdog(&sc->sc_ic); | 7535 | ieee80211_watchdog(&sc->sc_ic); | |
7536 | } | 7536 | } | |
7537 | 7537 | |||
7538 | static void | 7538 | static void | |
7539 | bwi_stop(struct ifnet *ifp, int state_chg) | 7539 | bwi_stop(struct ifnet *ifp, int state_chg) | |
7540 | { | 7540 | { | |
7541 | struct bwi_softc *sc = ifp->if_softc; | 7541 | struct bwi_softc *sc = ifp->if_softc; | |
7542 | struct ieee80211com *ic = &sc->sc_ic; | 7542 | struct ieee80211com *ic = &sc->sc_ic; | |
7543 | struct bwi_mac *mac; | 7543 | struct bwi_mac *mac; | |
7544 | int i, error, pwr_off = 0; | 7544 | int i, error, pwr_off = 0; | |
7545 | 7545 | |||
7546 | DPRINTF(sc, BWI_DBG_MISC, "%s\n", __func__); | 7546 | DPRINTF(sc, BWI_DBG_MISC, "%s\n", __func__); | |
7547 | 7547 | |||
7548 | if (state_chg) | 7548 | if (state_chg) | |
7549 | ieee80211_new_state(ic, IEEE80211_S_INIT, -1); | 7549 | ieee80211_new_state(ic, IEEE80211_S_INIT, -1); | |
7550 | else | 7550 | else | |
7551 | bwi_newstate_begin(sc, IEEE80211_S_INIT); | 7551 | bwi_newstate_begin(sc, IEEE80211_S_INIT); | |
7552 | 7552 | |||
7553 | if (ifp->if_flags & IFF_RUNNING) { | 7553 | if (ifp->if_flags & IFF_RUNNING) { | |
7554 | KASSERT(sc->sc_cur_regwin->rw_type == BWI_REGWIN_T_MAC); | 7554 | KASSERT(sc->sc_cur_regwin->rw_type == BWI_REGWIN_T_MAC); | |
7555 | mac = (struct bwi_mac *)sc->sc_cur_regwin; | 7555 | mac = (struct bwi_mac *)sc->sc_cur_regwin; | |
7556 | 7556 | |||
7557 | bwi_disable_intrs(sc, BWI_ALL_INTRS); | 7557 | bwi_disable_intrs(sc, BWI_ALL_INTRS); | |
7558 | CSR_READ_4(sc, BWI_MAC_INTR_MASK); | 7558 | CSR_READ_4(sc, BWI_MAC_INTR_MASK); | |
7559 | bwi_mac_stop(mac); | 7559 | bwi_mac_stop(mac); | |
7560 | } | 7560 | } | |
7561 | 7561 | |||
7562 | for (i = 0; i < sc->sc_nmac; ++i) { | 7562 | for (i = 0; i < sc->sc_nmac; ++i) { | |
7563 | struct bwi_regwin *old_rw; | 7563 | struct bwi_regwin *old_rw; | |
7564 | 7564 | |||
7565 | mac = &sc->sc_mac[i]; | 7565 | mac = &sc->sc_mac[i]; | |
7566 | if ((mac->mac_flags & BWI_MAC_F_INITED) == 0) | 7566 | if ((mac->mac_flags & BWI_MAC_F_INITED) == 0) | |
7567 | continue; | 7567 | continue; | |
7568 | 7568 | |||
7569 | error = bwi_regwin_switch(sc, &mac->mac_regwin, &old_rw); | 7569 | error = bwi_regwin_switch(sc, &mac->mac_regwin, &old_rw); | |
7570 | if (error) | 7570 | if (error) | |
7571 | continue; | 7571 | continue; | |
7572 | 7572 | |||
7573 | bwi_mac_shutdown(mac); | 7573 | bwi_mac_shutdown(mac); | |
7574 | pwr_off = 1; | 7574 | pwr_off = 1; | |
7575 | 7575 | |||
7576 | bwi_regwin_switch(sc, old_rw, NULL); | 7576 | bwi_regwin_switch(sc, old_rw, NULL); | |
7577 | } | 7577 | } | |
7578 | 7578 | |||
7579 | if (pwr_off) | 7579 | if (pwr_off) | |
7580 | bwi_bbp_power_off(sc); | 7580 | bwi_bbp_power_off(sc); | |
7581 | 7581 | |||
7582 | sc->sc_tx_timer = 0; | 7582 | sc->sc_tx_timer = 0; | |
7583 | ifp->if_timer = 0; | 7583 | ifp->if_timer = 0; | |
7584 | ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); | 7584 | ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); | |
7585 | 7585 | |||
7586 | /* power off cardbus socket */ | 7586 | /* power off cardbus socket */ | |
7587 | if (sc->sc_disable != NULL) | 7587 | if (sc->sc_disable != NULL) | |
7588 | (sc->sc_disable)(sc, 0); | 7588 | (sc->sc_disable)(sc, 0); | |
7589 | 7589 | |||
7590 | return; | 7590 | return; | |
7591 | } | 7591 | } | |
7592 | 7592 | |||
7593 | static void | 7593 | static void | |
7594 | bwi_newstate_begin(struct bwi_softc *sc, enum ieee80211_state nstate) | 7594 | bwi_newstate_begin(struct bwi_softc *sc, enum ieee80211_state nstate) | |
7595 | { | 7595 | { | |
7596 | callout_stop(&sc->sc_scan_ch); | 7596 | callout_stop(&sc->sc_scan_ch); | |
7597 | callout_stop(&sc->sc_calib_ch); | 7597 | callout_stop(&sc->sc_calib_ch); | |
7598 | 7598 | |||
7599 | bwi_led_newstate(sc, nstate); | 7599 | bwi_led_newstate(sc, nstate); | |
7600 | 7600 | |||
7601 | if (nstate == IEEE80211_S_INIT) | 7601 | if (nstate == IEEE80211_S_INIT) | |
7602 | sc->sc_txpwrcb_type = BWI_TXPWR_INIT; | 7602 | sc->sc_txpwrcb_type = BWI_TXPWR_INIT; | |
7603 | } | 7603 | } | |
7604 | 7604 | |||
7605 | static int | 7605 | static int | |
7606 | bwi_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg) | 7606 | bwi_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg) | |
7607 | { | 7607 | { | |
7608 | struct bwi_softc *sc = ic->ic_ifp->if_softc; | 7608 | struct bwi_softc *sc = ic->ic_ifp->if_softc; | |
7609 | struct ieee80211_node *ni; | 7609 | struct ieee80211_node *ni; | |
7610 | int error; | 7610 | int error; | |
7611 | 7611 | |||
7612 | /* [TRC: XXX amrr] */ | 7612 | /* [TRC: XXX amrr] */ | |
7613 | callout_stop(&sc->sc_amrr_ch); | 7613 | callout_stop(&sc->sc_amrr_ch); | |
7614 | 7614 | |||
7615 | bwi_newstate_begin(sc, nstate); | 7615 | bwi_newstate_begin(sc, nstate); | |
7616 | 7616 | |||
7617 | if (nstate == IEEE80211_S_INIT) | 7617 | if (nstate == IEEE80211_S_INIT) | |
7618 | goto back; | 7618 | goto back; | |
7619 | 7619 | |||
7620 | /* [TRC: XXX What channel do we set this to? */ | 7620 | /* [TRC: XXX What channel do we set this to? */ | |
7621 | error = bwi_set_chan(sc, ic->ic_curchan); | 7621 | error = bwi_set_chan(sc, ic->ic_curchan); | |
7622 | if (error) { | 7622 | if (error) { | |
7623 | aprint_error_dev(sc->sc_dev, "can't set channel to %u\n", | 7623 | aprint_error_dev(sc->sc_dev, "can't set channel to %u\n", | |
7624 | ieee80211_chan2ieee(ic, ic->ic_curchan)); | 7624 | ieee80211_chan2ieee(ic, ic->ic_curchan)); | |
7625 | return (error); | 7625 | return (error); | |
7626 | } | 7626 | } | |
7627 | 7627 | |||
7628 | if (ic->ic_opmode == IEEE80211_M_MONITOR) { | 7628 | if (ic->ic_opmode == IEEE80211_M_MONITOR) { | |
7629 | /* Nothing to do */ | 7629 | /* Nothing to do */ | |
7630 | } else if (nstate == IEEE80211_S_RUN) { | 7630 | } else if (nstate == IEEE80211_S_RUN) { | |
7631 | struct bwi_mac *mac; | 7631 | struct bwi_mac *mac; | |
7632 | 7632 | |||
7633 | ni = ic->ic_bss; | 7633 | ni = ic->ic_bss; | |
7634 | 7634 | |||
7635 | bwi_set_bssid(sc, ic->ic_bss->ni_bssid); | 7635 | bwi_set_bssid(sc, ic->ic_bss->ni_bssid); | |
7636 | 7636 | |||
7637 | KASSERT(sc->sc_cur_regwin->rw_type == BWI_REGWIN_T_MAC); | 7637 | KASSERT(sc->sc_cur_regwin->rw_type == BWI_REGWIN_T_MAC); | |
7638 | mac = (struct bwi_mac *)sc->sc_cur_regwin; | 7638 | mac = (struct bwi_mac *)sc->sc_cur_regwin; | |
7639 | 7639 | |||
7640 | /* Initial TX power calibration */ | 7640 | /* Initial TX power calibration */ | |
7641 | bwi_mac_calibrate_txpower(mac, BWI_TXPWR_INIT); | 7641 | bwi_mac_calibrate_txpower(mac, BWI_TXPWR_INIT); | |
7642 | #ifdef notyet | 7642 | #ifdef notyet | |
7643 | sc->sc_txpwrcb_type = BWI_TXPWR_FORCE; | 7643 | sc->sc_txpwrcb_type = BWI_TXPWR_FORCE; | |
7644 | #else | 7644 | #else | |
7645 | sc->sc_txpwrcb_type = BWI_TXPWR_CALIB; | 7645 | sc->sc_txpwrcb_type = BWI_TXPWR_CALIB; | |
7646 | #endif | 7646 | #endif | |
7647 | /* [TRC: XXX amrr] */ | 7647 | /* [TRC: XXX amrr] */ | |
7648 | if (ic->ic_opmode == IEEE80211_M_STA) { | 7648 | if (ic->ic_opmode == IEEE80211_M_STA) { | |
7649 | /* fake a join to init the tx rate */ | 7649 | /* fake a join to init the tx rate */ | |
7650 | bwi_newassoc(ni, 1); | 7650 | bwi_newassoc(ni, 1); | |
7651 | } | 7651 | } | |
7652 | 7652 | |||
7653 | if (ic->ic_opmode != IEEE80211_M_MONITOR) { | 7653 | if (ic->ic_opmode != IEEE80211_M_MONITOR) { | |
7654 | /* start automatic rate control timer */ | 7654 | /* start automatic rate control timer */ | |
7655 | if (ic->ic_fixed_rate == -1) | 7655 | if (ic->ic_fixed_rate == -1) | |
7656 | callout_schedule(&sc->sc_amrr_ch, hz / 2); | 7656 | callout_schedule(&sc->sc_amrr_ch, hz / 2); | |
7657 | } | 7657 | } | |
7658 | } else | 7658 | } else | |
7659 | bwi_set_bssid(sc, bwi_zero_addr); | 7659 | bwi_set_bssid(sc, bwi_zero_addr); | |
7660 | 7660 | |||
7661 | back: | 7661 | back: | |
7662 | error = (sc->sc_newstate)(ic, nstate, arg); | 7662 | error = (sc->sc_newstate)(ic, nstate, arg); | |
7663 | 7663 | |||
7664 | if (nstate == IEEE80211_S_SCAN) { | 7664 | if (nstate == IEEE80211_S_SCAN) { | |
7665 | callout_schedule(&sc->sc_scan_ch, | 7665 | callout_schedule(&sc->sc_scan_ch, | |
7666 | (sc->sc_dwell_time * hz) / 1000); | 7666 | (sc->sc_dwell_time * hz) / 1000); | |
7667 | } else if (nstate == IEEE80211_S_RUN) { | 7667 | } else if (nstate == IEEE80211_S_RUN) { | |
7668 | /* XXX 15 seconds */ | 7668 | /* XXX 15 seconds */ | |
7669 | callout_schedule(&sc->sc_calib_ch, hz); | 7669 | callout_schedule(&sc->sc_calib_ch, hz); | |
7670 | } | 7670 | } | |
7671 | 7671 | |||
7672 | return (error); | 7672 | return (error); | |
7673 | } | 7673 | } | |
7674 | 7674 | |||
7675 | static int | 7675 | static int | |
7676 | bwi_media_change(struct ifnet *ifp) | 7676 | bwi_media_change(struct ifnet *ifp) | |
7677 | { | 7677 | { | |
7678 | int error; | 7678 | int error; | |
7679 | 7679 | |||
7680 | error = ieee80211_media_change(ifp); | 7680 | error = ieee80211_media_change(ifp); | |
7681 | if (error != ENETRESET) | 7681 | if (error != ENETRESET) | |
7682 | return (error); | 7682 | return (error); | |
7683 | 7683 | |||
7684 | if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) == (IFF_UP | IFF_RUNNING)) | 7684 | if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) == (IFF_UP | IFF_RUNNING)) | |
7685 | bwi_init(ifp); | 7685 | bwi_init(ifp); | |
7686 | 7686 | |||
7687 | return (0); | 7687 | return (0); | |
7688 | } | 7688 | } | |
7689 | 7689 | |||
7690 | /* [TRC: XXX amrr] */ | 7690 | /* [TRC: XXX amrr] */ | |
7691 | static void | 7691 | static void | |
7692 | bwi_iter_func(void *arg, struct ieee80211_node *ni) | 7692 | bwi_iter_func(void *arg, struct ieee80211_node *ni) | |
7693 | { | 7693 | { | |
7694 | struct bwi_softc *sc = arg; | 7694 | struct bwi_softc *sc = arg; | |
7695 | struct bwi_node *bn = (struct bwi_node *)ni; | 7695 | struct bwi_node *bn = (struct bwi_node *)ni; | |
7696 | 7696 | |||
7697 | ieee80211_amrr_choose(&sc->sc_amrr, ni, &bn->amn); | 7697 | ieee80211_amrr_choose(&sc->sc_amrr, ni, &bn->amn); | |
7698 | } | 7698 | } | |
7699 | 7699 | |||
7700 | static void | 7700 | static void | |
7701 | bwi_amrr_timeout(void *arg) | 7701 | bwi_amrr_timeout(void *arg) | |
7702 | { | 7702 | { | |
7703 | struct bwi_softc *sc = arg; | 7703 | struct bwi_softc *sc = arg; | |
7704 | struct ieee80211com *ic = &sc->sc_ic; | 7704 | struct ieee80211com *ic = &sc->sc_ic; | |
7705 | int s; | 7705 | int s; | |
7706 | 7706 | |||
7707 | s = splnet(); | 7707 | s = splnet(); | |
7708 | if (ic->ic_opmode == IEEE80211_M_STA) | 7708 | if (ic->ic_opmode == IEEE80211_M_STA) | |
7709 | bwi_iter_func(sc, ic->ic_bss); | 7709 | bwi_iter_func(sc, ic->ic_bss); | |
7710 | else | 7710 | else | |
7711 | /* [TRC: XXX I'm making a wild guess about what to | 7711 | /* [TRC: XXX I'm making a wild guess about what to | |
7712 | supply for the node table.] */ | 7712 | supply for the node table.] */ | |
7713 | ieee80211_iterate_nodes(&ic->ic_sta, bwi_iter_func, sc); | 7713 | ieee80211_iterate_nodes(&ic->ic_sta, bwi_iter_func, sc); | |
7714 | 7714 | |||
7715 | callout_schedule(&sc->sc_amrr_ch, hz / 2); | 7715 | callout_schedule(&sc->sc_amrr_ch, hz / 2); | |
7716 | splx(s); | 7716 | splx(s); | |
7717 | } | 7717 | } | |
7718 | 7718 | |||
7719 | static void | 7719 | static void | |
7720 | bwi_newassoc(struct ieee80211_node *ni, int isnew) | 7720 | bwi_newassoc(struct ieee80211_node *ni, int isnew) | |
7721 | { | 7721 | { | |
7722 | struct ieee80211com *ic = ni->ni_ic; | 7722 | struct ieee80211com *ic = ni->ni_ic; | |
7723 | struct bwi_softc *sc = ic->ic_ifp->if_softc; | 7723 | struct bwi_softc *sc = ic->ic_ifp->if_softc; | |
7724 | int i; | 7724 | int i; | |
7725 | 7725 | |||
7726 | DPRINTF(sc, BWI_DBG_STATION, "%s\n", __func__); | 7726 | DPRINTF(sc, BWI_DBG_STATION, "%s\n", __func__); | |
7727 | 7727 | |||
7728 | ieee80211_amrr_node_init(&sc->sc_amrr, &((struct bwi_node *)ni)->amn); | 7728 | ieee80211_amrr_node_init(&sc->sc_amrr, &((struct bwi_node *)ni)->amn); | |
7729 | 7729 | |||
7730 | /* set rate to some reasonable initial value */ | 7730 | /* set rate to some reasonable initial value */ | |
7731 | for (i = ni->ni_rates.rs_nrates - 1; | 7731 | for (i = ni->ni_rates.rs_nrates - 1; | |
7732 | i > 0 && (ni->ni_rates.rs_rates[i] & IEEE80211_RATE_VAL) > 72; | 7732 | i > 0 && (ni->ni_rates.rs_rates[i] & IEEE80211_RATE_VAL) > 72; | |
7733 | i--); | 7733 | i--); | |
7734 | 7734 | |||
7735 | ni->ni_txrate = i; | 7735 | ni->ni_txrate = i; | |
7736 | } | 7736 | } | |
7737 | 7737 | |||
7738 | static struct ieee80211_node * | 7738 | static struct ieee80211_node * | |
7739 | bwi_node_alloc(struct ieee80211_node_table *nt) | 7739 | bwi_node_alloc(struct ieee80211_node_table *nt) | |
7740 | { | 7740 | { | |
7741 | struct bwi_node *bn; | 7741 | struct bwi_node *bn; | |
7742 | 7742 | |||
7743 | bn = malloc(sizeof(struct bwi_node), M_80211_NODE, M_NOWAIT | M_ZERO); | 7743 | bn = malloc(sizeof(struct bwi_node), M_80211_NODE, M_NOWAIT | M_ZERO); | |
7744 | 7744 | |||
7745 | return ((struct ieee80211_node *)bn); | 7745 | return ((struct ieee80211_node *)bn); | |
7746 | } | 7746 | } | |
7747 | /* [TRC: XXX amrr end] */ | 7747 | /* [TRC: XXX amrr end] */ | |
7748 | 7748 | |||
7749 | static int | 7749 | static int | |
7750 | bwi_dma_alloc(struct bwi_softc *sc) | 7750 | bwi_dma_alloc(struct bwi_softc *sc) | |
7751 | { | 7751 | { | |
7752 | int error, i, has_txstats; | 7752 | int error, i, has_txstats; | |
7753 | /* [TRC: XXX DragonFlyBSD adjusts the low address for different | 7753 | /* [TRC: XXX DragonFlyBSD adjusts the low address for different | |
7754 | bus spaces. Should we?] */ | 7754 | bus spaces. Should we?] */ | |
7755 | bus_size_t tx_ring_sz, rx_ring_sz, desc_sz = 0; | 7755 | bus_size_t tx_ring_sz, rx_ring_sz, desc_sz = 0; | |
7756 | uint32_t txrx_ctrl_step = 0; | 7756 | uint32_t txrx_ctrl_step = 0; | |
7757 | 7757 | |||
7758 | has_txstats = 0; | 7758 | has_txstats = 0; | |
7759 | for (i = 0; i < sc->sc_nmac; ++i) { | 7759 | for (i = 0; i < sc->sc_nmac; ++i) { | |
7760 | if (sc->sc_mac[i].mac_flags & BWI_MAC_F_HAS_TXSTATS) { | 7760 | if (sc->sc_mac[i].mac_flags & BWI_MAC_F_HAS_TXSTATS) { | |
7761 | has_txstats = 1; | 7761 | has_txstats = 1; | |
7762 | break; | 7762 | break; | |
7763 | } | 7763 | } | |
7764 | } | 7764 | } | |
7765 | 7765 | |||
7766 | switch (sc->sc_bus_space) { | 7766 | switch (sc->sc_bus_space) { | |
7767 | case BWI_BUS_SPACE_30BIT: | 7767 | case BWI_BUS_SPACE_30BIT: | |
7768 | case BWI_BUS_SPACE_32BIT: | 7768 | case BWI_BUS_SPACE_32BIT: | |
7769 | desc_sz = sizeof(struct bwi_desc32); | 7769 | desc_sz = sizeof(struct bwi_desc32); | |
7770 | txrx_ctrl_step = 0x20; | 7770 | txrx_ctrl_step = 0x20; | |
7771 | 7771 | |||
7772 | sc->sc_init_tx_ring = bwi_init_tx_ring32; | 7772 | sc->sc_init_tx_ring = bwi_init_tx_ring32; | |
7773 | sc->sc_free_tx_ring = bwi_free_tx_ring32; | 7773 | sc->sc_free_tx_ring = bwi_free_tx_ring32; | |
7774 | sc->sc_init_rx_ring = bwi_init_rx_ring32; | 7774 | sc->sc_init_rx_ring = bwi_init_rx_ring32; | |
7775 | sc->sc_free_rx_ring = bwi_free_rx_ring32; | 7775 | sc->sc_free_rx_ring = bwi_free_rx_ring32; | |
7776 | sc->sc_setup_rxdesc = bwi_setup_rx_desc32; | 7776 | sc->sc_setup_rxdesc = bwi_setup_rx_desc32; | |
7777 | sc->sc_setup_txdesc = bwi_setup_tx_desc32; | 7777 | sc->sc_setup_txdesc = bwi_setup_tx_desc32; | |
7778 | sc->sc_rxeof = bwi_rxeof32; | 7778 | sc->sc_rxeof = bwi_rxeof32; | |
7779 | sc->sc_start_tx = bwi_start_tx32; | 7779 | sc->sc_start_tx = bwi_start_tx32; | |
7780 | if (has_txstats) { | 7780 | if (has_txstats) { | |
7781 | sc->sc_init_txstats = bwi_init_txstats32; | 7781 | sc->sc_init_txstats = bwi_init_txstats32; | |
7782 | sc->sc_free_txstats = bwi_free_txstats32; | 7782 | sc->sc_free_txstats = bwi_free_txstats32; | |
7783 | sc->sc_txeof_status = bwi_txeof_status32; | 7783 | sc->sc_txeof_status = bwi_txeof_status32; | |
7784 | } | 7784 | } | |
7785 | break; | 7785 | break; | |
7786 | 7786 | |||
7787 | case BWI_BUS_SPACE_64BIT: | 7787 | case BWI_BUS_SPACE_64BIT: | |
7788 | desc_sz = sizeof(struct bwi_desc64); | 7788 | desc_sz = sizeof(struct bwi_desc64); | |
7789 | txrx_ctrl_step = 0x40; | 7789 | txrx_ctrl_step = 0x40; | |
7790 | 7790 | |||
7791 | sc->sc_init_tx_ring = bwi_init_tx_ring64; | 7791 | sc->sc_init_tx_ring = bwi_init_tx_ring64; | |
7792 | sc->sc_free_tx_ring = bwi_free_tx_ring64; | 7792 | sc->sc_free_tx_ring = bwi_free_tx_ring64; | |
7793 | sc->sc_init_rx_ring = bwi_init_rx_ring64; | 7793 | sc->sc_init_rx_ring = bwi_init_rx_ring64; | |
7794 | sc->sc_free_rx_ring = bwi_free_rx_ring64; | 7794 | sc->sc_free_rx_ring = bwi_free_rx_ring64; | |
7795 | sc->sc_setup_rxdesc = bwi_setup_rx_desc64; | 7795 | sc->sc_setup_rxdesc = bwi_setup_rx_desc64; | |
7796 | sc->sc_setup_txdesc = bwi_setup_tx_desc64; | 7796 | sc->sc_setup_txdesc = bwi_setup_tx_desc64; | |
7797 | sc->sc_rxeof = bwi_rxeof64; | 7797 | sc->sc_rxeof = bwi_rxeof64; | |
7798 | sc->sc_start_tx = bwi_start_tx64; | 7798 | sc->sc_start_tx = bwi_start_tx64; | |
7799 | if (has_txstats) { | 7799 | if (has_txstats) { | |
7800 | sc->sc_init_txstats = bwi_init_txstats64; | 7800 | sc->sc_init_txstats = bwi_init_txstats64; | |
7801 | sc->sc_free_txstats = bwi_free_txstats64; | 7801 | sc->sc_free_txstats = bwi_free_txstats64; | |
7802 | sc->sc_txeof_status = bwi_txeof_status64; | 7802 | sc->sc_txeof_status = bwi_txeof_status64; | |
7803 | } | 7803 | } | |
7804 | break; | 7804 | break; | |
7805 | } | 7805 | } | |
7806 | 7806 | |||
7807 | KASSERT(desc_sz != 0); | 7807 | KASSERT(desc_sz != 0); | |
7808 | KASSERT(txrx_ctrl_step != 0); | 7808 | KASSERT(txrx_ctrl_step != 0); | |
7809 | 7809 | |||
7810 | tx_ring_sz = roundup(desc_sz * BWI_TX_NDESC, BWI_RING_ALIGN); | 7810 | tx_ring_sz = roundup(desc_sz * BWI_TX_NDESC, BWI_RING_ALIGN); | |
7811 | rx_ring_sz = roundup(desc_sz * BWI_RX_NDESC, BWI_RING_ALIGN); | 7811 | rx_ring_sz = roundup(desc_sz * BWI_RX_NDESC, BWI_RING_ALIGN); | |
7812 | 7812 | |||
7813 | /* [TRC: XXX Using OpenBSD's code, which is rather different | 7813 | /* [TRC: XXX Using OpenBSD's code, which is rather different | |
7814 | from DragonFlyBSD's.] */ | 7814 | from DragonFlyBSD's.] */ | |
7815 | #define TXRX_CTRL(idx) (BWI_TXRX_CTRL_BASE + (idx) * txrx_ctrl_step) | 7815 | #define TXRX_CTRL(idx) (BWI_TXRX_CTRL_BASE + (idx) * txrx_ctrl_step) | |
7816 | /* | 7816 | /* | |
7817 | * Create TX ring DMA stuffs | 7817 | * Create TX ring DMA stuffs | |
7818 | */ | 7818 | */ | |
7819 | for (i = 0; i < BWI_TX_NRING; ++i) { | 7819 | for (i = 0; i < BWI_TX_NRING; ++i) { | |
7820 | error = bus_dmamap_create(sc->sc_dmat, tx_ring_sz, 1, | 7820 | error = bus_dmamap_create(sc->sc_dmat, tx_ring_sz, 1, | |
7821 | tx_ring_sz, 0, BUS_DMA_NOWAIT, | 7821 | tx_ring_sz, 0, BUS_DMA_NOWAIT, | |
7822 | &sc->sc_tx_rdata[i].rdata_dmap); | 7822 | &sc->sc_tx_rdata[i].rdata_dmap); | |
7823 | if (error) { | 7823 | if (error) { | |
7824 | aprint_error_dev(sc->sc_dev, | 7824 | aprint_error_dev(sc->sc_dev, | |
7825 | "%dth TX ring DMA create failed\n", i); | 7825 | "%dth TX ring DMA create failed\n", i); | |
7826 | return (error); | 7826 | return (error); | |
7827 | } | 7827 | } | |
7828 | error = bwi_dma_ring_alloc(sc, | 7828 | error = bwi_dma_ring_alloc(sc, | |
7829 | &sc->sc_tx_rdata[i], tx_ring_sz, TXRX_CTRL(i)); | 7829 | &sc->sc_tx_rdata[i], tx_ring_sz, TXRX_CTRL(i)); | |
7830 | if (error) { | 7830 | if (error) { | |
7831 | aprint_error_dev(sc->sc_dev, | 7831 | aprint_error_dev(sc->sc_dev, | |
7832 | "%dth TX ring DMA alloc failed\n", i); | 7832 | "%dth TX ring DMA alloc failed\n", i); | |
7833 | return (error); | 7833 | return (error); | |
7834 | } | 7834 | } | |
7835 | } | 7835 | } | |
7836 | 7836 | |||
7837 | /* | 7837 | /* | |
7838 | * Create RX ring DMA stuffs | 7838 | * Create RX ring DMA stuffs | |
7839 | */ | 7839 | */ | |
7840 | error = bus_dmamap_create(sc->sc_dmat, rx_ring_sz, 1, | 7840 | error = bus_dmamap_create(sc->sc_dmat, rx_ring_sz, 1, | |
7841 | rx_ring_sz, 0, BUS_DMA_NOWAIT, | 7841 | rx_ring_sz, 0, BUS_DMA_NOWAIT, | |
7842 | &sc->sc_rx_rdata.rdata_dmap); | 7842 | &sc->sc_rx_rdata.rdata_dmap); | |
7843 | if (error) { | 7843 | if (error) { | |
7844 | aprint_error_dev(sc->sc_dev, "RX ring DMA create failed\n"); | 7844 | aprint_error_dev(sc->sc_dev, "RX ring DMA create failed\n"); | |
7845 | return (error); | 7845 | return (error); | |
7846 | } | 7846 | } | |
7847 | 7847 | |||
7848 | error = bwi_dma_ring_alloc(sc, &sc->sc_rx_rdata, | 7848 | error = bwi_dma_ring_alloc(sc, &sc->sc_rx_rdata, | |
7849 | rx_ring_sz, TXRX_CTRL(0)); | 7849 | rx_ring_sz, TXRX_CTRL(0)); | |
7850 | if (error) { | 7850 | if (error) { | |
7851 | aprint_error_dev(sc->sc_dev, "RX ring DMA alloc failed\n"); | 7851 | aprint_error_dev(sc->sc_dev, "RX ring DMA alloc failed\n"); | |
7852 | return (error); | 7852 | return (error); | |
7853 | } | 7853 | } | |
7854 | 7854 | |||
7855 | if (has_txstats) { | 7855 | if (has_txstats) { | |
7856 | error = bwi_dma_txstats_alloc(sc, TXRX_CTRL(3), desc_sz); | 7856 | error = bwi_dma_txstats_alloc(sc, TXRX_CTRL(3), desc_sz); | |
7857 | if (error) { | 7857 | if (error) { | |
7858 | aprint_error_dev(sc->sc_dev, | 7858 | aprint_error_dev(sc->sc_dev, | |
7859 | "TX stats DMA alloc failed\n"); | 7859 | "TX stats DMA alloc failed\n"); | |
7860 | return (error); | 7860 | return (error); | |
7861 | } | 7861 | } | |
7862 | } | 7862 | } | |
7863 | #undef TXRX_CTRL | 7863 | #undef TXRX_CTRL | |
7864 | 7864 | |||
7865 | return (bwi_dma_mbuf_create(sc)); | 7865 | return (bwi_dma_mbuf_create(sc)); | |
7866 | } | 7866 | } | |
7867 | 7867 | |||
7868 | static void | 7868 | static void | |
7869 | bwi_dma_free(struct bwi_softc *sc) | 7869 | bwi_dma_free(struct bwi_softc *sc) | |
7870 | { | 7870 | { | |
7871 | int i; | 7871 | int i; | |
7872 | 7872 | |||
7873 | for (i = 0; i < BWI_TX_NRING; ++i) | 7873 | for (i = 0; i < BWI_TX_NRING; ++i) | |
7874 | bwi_ring_data_free(&sc->sc_tx_rdata[i], sc); | 7874 | bwi_ring_data_free(&sc->sc_tx_rdata[i], sc); | |
7875 | 7875 | |||
7876 | bwi_ring_data_free(&sc->sc_rx_rdata, sc); | 7876 | bwi_ring_data_free(&sc->sc_rx_rdata, sc); | |
7877 | bwi_dma_txstats_free(sc); | 7877 | bwi_dma_txstats_free(sc); | |
7878 | bwi_dma_mbuf_destroy(sc, BWI_TX_NRING, 1); | 7878 | bwi_dma_mbuf_destroy(sc, BWI_TX_NRING, 1); | |
7879 | } | 7879 | } | |
7880 | 7880 | |||
7881 | static void | 7881 | static void | |
7882 | bwi_ring_data_free(struct bwi_ring_data *rd, struct bwi_softc *sc) | 7882 | bwi_ring_data_free(struct bwi_ring_data *rd, struct bwi_softc *sc) | |
7883 | { | 7883 | { | |
7884 | if (rd->rdata_desc != NULL) { | 7884 | if (rd->rdata_desc != NULL) { | |
7885 | bus_dmamap_unload(sc->sc_dmat, rd->rdata_dmap); | 7885 | bus_dmamap_unload(sc->sc_dmat, rd->rdata_dmap); | |
7886 | bus_dmamem_free(sc->sc_dmat, &rd->rdata_seg, 1); | 7886 | bus_dmamem_free(sc->sc_dmat, &rd->rdata_seg, 1); | |
7887 | } | 7887 | } | |
7888 | } | 7888 | } | |
7889 | 7889 | |||
7890 | static int | 7890 | static int | |
7891 | bwi_dma_ring_alloc(struct bwi_softc *sc, | 7891 | bwi_dma_ring_alloc(struct bwi_softc *sc, | |
7892 | struct bwi_ring_data *rd, bus_size_t size, uint32_t txrx_ctrl) | 7892 | struct bwi_ring_data *rd, bus_size_t size, uint32_t txrx_ctrl) | |
7893 | { | 7893 | { | |
7894 | int error, nsegs; | 7894 | int error, nsegs; | |
7895 | 7895 | |||
7896 | error = bus_dmamem_alloc(sc->sc_dmat, size, BWI_ALIGN, 0, | 7896 | error = bus_dmamem_alloc(sc->sc_dmat, size, BWI_ALIGN, 0, | |
7897 | &rd->rdata_seg, 1, &nsegs, BUS_DMA_NOWAIT); | 7897 | &rd->rdata_seg, 1, &nsegs, BUS_DMA_NOWAIT); | |
7898 | if (error) { | 7898 | if (error) { | |
7899 | aprint_error_dev(sc->sc_dev, "can't allocate DMA mem\n"); | 7899 | aprint_error_dev(sc->sc_dev, "can't allocate DMA mem\n"); | |
7900 | return (error); | 7900 | return (error); | |
7901 | } | 7901 | } | |
7902 | 7902 | |||
7903 | error = bus_dmamem_map(sc->sc_dmat, &rd->rdata_seg, nsegs, | 7903 | error = bus_dmamem_map(sc->sc_dmat, &rd->rdata_seg, nsegs, | |
7904 | size, (void **)&rd->rdata_desc, BUS_DMA_NOWAIT); | 7904 | size, (void **)&rd->rdata_desc, BUS_DMA_NOWAIT); | |
7905 | if (error) { | 7905 | if (error) { | |
7906 | aprint_error_dev(sc->sc_dev, "can't map DMA mem\n"); | 7906 | aprint_error_dev(sc->sc_dev, "can't map DMA mem\n"); | |
7907 | return (error); | 7907 | return (error); | |
7908 | } | 7908 | } | |
7909 | 7909 | |||
7910 | error = bus_dmamap_load(sc->sc_dmat, rd->rdata_dmap, rd->rdata_desc, | 7910 | error = bus_dmamap_load(sc->sc_dmat, rd->rdata_dmap, rd->rdata_desc, | |
7911 | size, NULL, BUS_DMA_WAITOK); | 7911 | size, NULL, BUS_DMA_WAITOK); | |
7912 | if (error) { | 7912 | if (error) { | |
7913 | aprint_error_dev(sc->sc_dev, "can't load DMA mem\n"); | 7913 | aprint_error_dev(sc->sc_dev, "can't load DMA mem\n"); | |
7914 | bus_dmamem_free(sc->sc_dmat, &rd->rdata_seg, nsegs); | 7914 | bus_dmamem_free(sc->sc_dmat, &rd->rdata_seg, nsegs); | |
7915 | rd->rdata_desc = NULL; | 7915 | rd->rdata_desc = NULL; | |
7916 | return (error); | 7916 | return (error); | |
7917 | } | 7917 | } | |
7918 | 7918 | |||
7919 | rd->rdata_paddr = rd->rdata_dmap->dm_segs[0].ds_addr; | 7919 | rd->rdata_paddr = rd->rdata_dmap->dm_segs[0].ds_addr; | |
7920 | rd->rdata_txrx_ctrl = txrx_ctrl; | 7920 | rd->rdata_txrx_ctrl = txrx_ctrl; | |
7921 | 7921 | |||
7922 | return (0); | 7922 | return (0); | |
7923 | } | 7923 | } | |
7924 | 7924 | |||
7925 | static int | 7925 | static int | |
7926 | bwi_dma_txstats_alloc(struct bwi_softc *sc, uint32_t ctrl_base, | 7926 | bwi_dma_txstats_alloc(struct bwi_softc *sc, uint32_t ctrl_base, | |
7927 | bus_size_t desc_sz) | 7927 | bus_size_t desc_sz) | |
7928 | { | 7928 | { | |
7929 | struct bwi_txstats_data *st; | 7929 | struct bwi_txstats_data *st; | |
7930 | bus_size_t dma_size; | 7930 | bus_size_t dma_size; | |
7931 | int error, nsegs; | 7931 | int error, nsegs; | |
7932 | 7932 | |||
7933 | st = malloc(sizeof(*st), M_DEVBUF, M_WAITOK | M_ZERO); | 7933 | st = malloc(sizeof(*st), M_DEVBUF, M_WAITOK | M_ZERO); | |
7934 | sc->sc_txstats = st; | 7934 | sc->sc_txstats = st; | |
7935 | 7935 | |||
7936 | /* | 7936 | /* | |
7937 | * Create TX stats descriptor DMA stuffs | 7937 | * Create TX stats descriptor DMA stuffs | |
7938 | */ | 7938 | */ | |
7939 | dma_size = roundup(desc_sz * BWI_TXSTATS_NDESC, BWI_RING_ALIGN); | 7939 | dma_size = roundup(desc_sz * BWI_TXSTATS_NDESC, BWI_RING_ALIGN); | |
7940 | 7940 | |||
7941 | error = bus_dmamap_create(sc->sc_dmat, dma_size, 1, dma_size, 0, | 7941 | error = bus_dmamap_create(sc->sc_dmat, dma_size, 1, dma_size, 0, | |
7942 | BUS_DMA_NOWAIT, &st->stats_ring_dmap); | 7942 | BUS_DMA_NOWAIT, &st->stats_ring_dmap); | |
7943 | if (error) { | 7943 | if (error) { | |
7944 | aprint_error_dev(sc->sc_dev, | 7944 | aprint_error_dev(sc->sc_dev, | |
7945 | "can't create txstats ring DMA mem\n"); | 7945 | "can't create txstats ring DMA mem\n"); | |
7946 | return (error); | 7946 | return (error); | |
7947 | } | 7947 | } | |
7948 | 7948 | |||
7949 | error = bus_dmamem_alloc(sc->sc_dmat, dma_size, BWI_RING_ALIGN, 0, | 7949 | error = bus_dmamem_alloc(sc->sc_dmat, dma_size, BWI_RING_ALIGN, 0, | |
7950 | &st->stats_ring_seg, 1, &nsegs, BUS_DMA_NOWAIT); | 7950 | &st->stats_ring_seg, 1, &nsegs, BUS_DMA_NOWAIT); | |
7951 | if (error) { | 7951 | if (error) { | |
7952 | aprint_error_dev(sc->sc_dev, | 7952 | aprint_error_dev(sc->sc_dev, | |
7953 | "can't allocate txstats ring DMA mem\n"); | 7953 | "can't allocate txstats ring DMA mem\n"); | |
7954 | return (error); | 7954 | return (error); | |
7955 | } | 7955 | } | |
7956 | 7956 | |||
7957 | error = bus_dmamem_map(sc->sc_dmat, &st->stats_ring_seg, nsegs, | 7957 | error = bus_dmamem_map(sc->sc_dmat, &st->stats_ring_seg, nsegs, | |
7958 | dma_size, (void **)&st->stats_ring, BUS_DMA_NOWAIT); | 7958 | dma_size, (void **)&st->stats_ring, BUS_DMA_NOWAIT); | |
7959 | if (error) { | 7959 | if (error) { | |
7960 | aprint_error_dev(sc->sc_dev, | 7960 | aprint_error_dev(sc->sc_dev, | |
7961 | "can't map txstats ring DMA mem\n"); | 7961 | "can't map txstats ring DMA mem\n"); | |
7962 | return (error); | 7962 | return (error); | |
7963 | } | 7963 | } | |
7964 | 7964 | |||
7965 | error = bus_dmamap_load(sc->sc_dmat, st->stats_ring_dmap, | 7965 | error = bus_dmamap_load(sc->sc_dmat, st->stats_ring_dmap, | |
7966 | st->stats_ring, dma_size, NULL, BUS_DMA_WAITOK); | 7966 | st->stats_ring, dma_size, NULL, BUS_DMA_WAITOK); | |
7967 | if (error) { | 7967 | if (error) { | |
7968 | aprint_error_dev(sc->sc_dev, | 7968 | aprint_error_dev(sc->sc_dev, | |
7969 | "can't load txstats ring DMA mem\n"); | 7969 | "can't load txstats ring DMA mem\n"); | |
7970 | bus_dmamem_free(sc->sc_dmat, &st->stats_ring_seg, nsegs); | 7970 | bus_dmamem_free(sc->sc_dmat, &st->stats_ring_seg, nsegs); | |
7971 | return (error); | 7971 | return (error); | |
7972 | } | 7972 | } | |
7973 | 7973 | |||
7974 | memset(st->stats_ring, 0, dma_size); | 7974 | memset(st->stats_ring, 0, dma_size); | |
7975 | st->stats_ring_paddr = st->stats_ring_dmap->dm_segs[0].ds_addr; | 7975 | st->stats_ring_paddr = st->stats_ring_dmap->dm_segs[0].ds_addr; | |
7976 | 7976 | |||
7977 | /* | 7977 | /* | |
7978 | * Create TX stats DMA stuffs | 7978 | * Create TX stats DMA stuffs | |
7979 | */ | 7979 | */ | |
7980 | dma_size = roundup(sizeof(struct bwi_txstats) * BWI_TXSTATS_NDESC, | 7980 | dma_size = roundup(sizeof(struct bwi_txstats) * BWI_TXSTATS_NDESC, | |
7981 | BWI_ALIGN); | 7981 | BWI_ALIGN); | |
7982 | 7982 | |||
7983 | error = bus_dmamap_create(sc->sc_dmat, dma_size, 1, dma_size, 0, | 7983 | error = bus_dmamap_create(sc->sc_dmat, dma_size, 1, dma_size, 0, | |
7984 | BUS_DMA_NOWAIT, &st->stats_dmap); | 7984 | BUS_DMA_NOWAIT, &st->stats_dmap); | |
7985 | if (error) { | 7985 | if (error) { | |
7986 | aprint_error_dev(sc->sc_dev, | 7986 | aprint_error_dev(sc->sc_dev, | |
7987 | "can't create txstats ring DMA mem\n"); | 7987 | "can't create txstats ring DMA mem\n"); | |
7988 | return (error); | 7988 | return (error); | |
7989 | } | 7989 | } | |
7990 | 7990 | |||
7991 | error = bus_dmamem_alloc(sc->sc_dmat, dma_size, BWI_ALIGN, 0, | 7991 | error = bus_dmamem_alloc(sc->sc_dmat, dma_size, BWI_ALIGN, 0, | |
7992 | &st->stats_seg, 1, &nsegs, BUS_DMA_NOWAIT); | 7992 | &st->stats_seg, 1, &nsegs, BUS_DMA_NOWAIT); | |
7993 | if (error) { | 7993 | if (error) { | |
7994 | aprint_error_dev(sc->sc_dev, | 7994 | aprint_error_dev(sc->sc_dev, | |
7995 | "can't allocate txstats DMA mem\n"); | 7995 | "can't allocate txstats DMA mem\n"); | |
7996 | return (error); | 7996 | return (error); | |
7997 | } | 7997 | } | |
7998 | 7998 | |||
7999 | error = bus_dmamem_map(sc->sc_dmat, &st->stats_seg, nsegs, | 7999 | error = bus_dmamem_map(sc->sc_dmat, &st->stats_seg, nsegs, | |
8000 | dma_size, (void **)&st->stats, BUS_DMA_NOWAIT); | 8000 | dma_size, (void **)&st->stats, BUS_DMA_NOWAIT); | |
8001 | if (error) { | 8001 | if (error) { | |
8002 | aprint_error_dev(sc->sc_dev, "can't map txstats DMA mem\n"); | 8002 | aprint_error_dev(sc->sc_dev, "can't map txstats DMA mem\n"); | |
8003 | return (error); | 8003 | return (error); | |
8004 | } | 8004 | } | |
8005 | 8005 | |||
8006 | error = bus_dmamap_load(sc->sc_dmat, st->stats_dmap, st->stats, | 8006 | error = bus_dmamap_load(sc->sc_dmat, st->stats_dmap, st->stats, | |
8007 | dma_size, NULL, BUS_DMA_WAITOK); | 8007 | dma_size, NULL, BUS_DMA_WAITOK); | |
8008 | if (error) { | 8008 | if (error) { | |
8009 | aprint_error_dev(sc->sc_dev, "can't load txstats DMA mem\n"); | 8009 | aprint_error_dev(sc->sc_dev, "can't load txstats DMA mem\n"); | |
8010 | bus_dmamem_free(sc->sc_dmat, &st->stats_seg, nsegs); | 8010 | bus_dmamem_free(sc->sc_dmat, &st->stats_seg, nsegs); | |
8011 | return (error); | 8011 | return (error); | |
8012 | } | 8012 | } | |
8013 | 8013 | |||
8014 | memset(st->stats, 0, dma_size); | 8014 | memset(st->stats, 0, dma_size); | |
8015 | st->stats_paddr = st->stats_dmap->dm_segs[0].ds_addr; | 8015 | st->stats_paddr = st->stats_dmap->dm_segs[0].ds_addr; | |
8016 | st->stats_ctrl_base = ctrl_base; | 8016 | st->stats_ctrl_base = ctrl_base; | |
8017 | 8017 | |||
8018 | return (0); | 8018 | return (0); | |
8019 | } | 8019 | } | |
8020 | 8020 | |||
8021 | static void | 8021 | static void | |
8022 | bwi_dma_txstats_free(struct bwi_softc *sc) | 8022 | bwi_dma_txstats_free(struct bwi_softc *sc) | |
8023 | { | 8023 | { | |
8024 | struct bwi_txstats_data *st; | 8024 | struct bwi_txstats_data *st; | |
8025 | 8025 | |||
8026 | if (sc->sc_txstats == NULL) | 8026 | if (sc->sc_txstats == NULL) | |
8027 | return; | 8027 | return; | |
8028 | st = sc->sc_txstats; | 8028 | st = sc->sc_txstats; | |
8029 | 8029 | |||
8030 | bus_dmamap_unload(sc->sc_dmat, st->stats_ring_dmap); | 8030 | bus_dmamap_unload(sc->sc_dmat, st->stats_ring_dmap); | |
8031 | bus_dmamem_free(sc->sc_dmat, &st->stats_ring_seg, 1); | 8031 | bus_dmamem_free(sc->sc_dmat, &st->stats_ring_seg, 1); | |
8032 | 8032 | |||
8033 | bus_dmamap_unload(sc->sc_dmat, st->stats_dmap); | 8033 | bus_dmamap_unload(sc->sc_dmat, st->stats_dmap); | |
8034 | bus_dmamem_free(sc->sc_dmat, &st->stats_seg, 1); | 8034 | bus_dmamem_free(sc->sc_dmat, &st->stats_seg, 1); | |
8035 | 8035 | |||
8036 | free(st, M_DEVBUF); | 8036 | free(st, M_DEVBUF); | |
8037 | } | 8037 | } | |
8038 | 8038 | |||
8039 | static int | 8039 | static int | |
8040 | bwi_dma_mbuf_create(struct bwi_softc *sc) | 8040 | bwi_dma_mbuf_create(struct bwi_softc *sc) | |
8041 | { | 8041 | { | |
8042 | struct bwi_rxbuf_data *rbd = &sc->sc_rx_bdata; | 8042 | struct bwi_rxbuf_data *rbd = &sc->sc_rx_bdata; | |
8043 | int i, j, k, ntx, error; | 8043 | int i, j, k, ntx, error; | |
8044 | 8044 | |||
8045 | ntx = 0; | 8045 | ntx = 0; | |
8046 | 8046 | |||
8047 | /* | 8047 | /* | |
8048 | * Create TX mbuf DMA map | 8048 | * Create TX mbuf DMA map | |
8049 | */ | 8049 | */ | |
8050 | for (i = 0; i < BWI_TX_NRING; ++i) { | 8050 | for (i = 0; i < BWI_TX_NRING; ++i) { | |
8051 | struct bwi_txbuf_data *tbd = &sc->sc_tx_bdata[i]; | 8051 | struct bwi_txbuf_data *tbd = &sc->sc_tx_bdata[i]; | |
8052 | 8052 | |||
8053 | for (j = 0; j < BWI_TX_NDESC; ++j) { | 8053 | for (j = 0; j < BWI_TX_NDESC; ++j) { | |
8054 | error = bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1, MCLBYTES, | 8054 | error = bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1, MCLBYTES, | |
8055 | 0, BUS_DMA_NOWAIT, &tbd->tbd_buf[j].tb_dmap); | 8055 | 0, BUS_DMA_NOWAIT, &tbd->tbd_buf[j].tb_dmap); | |
8056 | if (error) { | 8056 | if (error) { | |
8057 | aprint_error_dev(sc->sc_dev, | 8057 | aprint_error_dev(sc->sc_dev, | |
8058 | "can't create %dth tbd, %dth DMA map\n", | 8058 | "can't create %dth tbd, %dth DMA map\n", | |
8059 | i, j); | 8059 | i, j); | |
8060 | ntx = i; | 8060 | ntx = i; | |
8061 | for (k = 0; k < j; ++k) { | 8061 | for (k = 0; k < j; ++k) { | |
8062 | bus_dmamap_destroy(sc->sc_dmat, | 8062 | bus_dmamap_destroy(sc->sc_dmat, | |
8063 | tbd->tbd_buf[k].tb_dmap); | 8063 | tbd->tbd_buf[k].tb_dmap); | |
8064 | } | 8064 | } | |
8065 | goto fail; | 8065 | goto fail; | |
8066 | } | 8066 | } | |
8067 | } | 8067 | } | |
8068 | } | 8068 | } | |
8069 | ntx = BWI_TX_NRING; | 8069 | ntx = BWI_TX_NRING; | |
8070 | 8070 | |||
8071 | /* | 8071 | /* | |
8072 | * Create RX mbuf DMA map and a spare DMA map | 8072 | * Create RX mbuf DMA map and a spare DMA map | |
8073 | */ | 8073 | */ | |
8074 | error = bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1, MCLBYTES, 0, | 8074 | error = bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1, MCLBYTES, 0, | |
8075 | BUS_DMA_NOWAIT, &rbd->rbd_tmp_dmap); | 8075 | BUS_DMA_NOWAIT, &rbd->rbd_tmp_dmap); | |
8076 | if (error) { | 8076 | if (error) { | |
8077 | aprint_error_dev(sc->sc_dev, | 8077 | aprint_error_dev(sc->sc_dev, | |
8078 | "can't create spare RX buf DMA map\n"); | 8078 | "can't create spare RX buf DMA map\n"); | |
8079 | goto fail; | 8079 | goto fail; | |
8080 | } | 8080 | } | |
8081 | 8081 | |||
8082 | for (j = 0; j < BWI_RX_NDESC; ++j) { | 8082 | for (j = 0; j < BWI_RX_NDESC; ++j) { | |
8083 | error = bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1, MCLBYTES, 0, | 8083 | error = bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1, MCLBYTES, 0, | |
8084 | BUS_DMA_NOWAIT, &rbd->rbd_buf[j].rb_dmap); | 8084 | BUS_DMA_NOWAIT, &rbd->rbd_buf[j].rb_dmap); | |
8085 | if (error) { | 8085 | if (error) { | |
8086 | aprint_error_dev(sc->sc_dev, | 8086 | aprint_error_dev(sc->sc_dev, | |
8087 | "can't create %dth RX buf DMA map\n", j); | 8087 | "can't create %dth RX buf DMA map\n", j); | |
8088 | 8088 | |||
8089 | for (k = 0; k < j; ++k) { | 8089 | for (k = 0; k < j; ++k) { | |
8090 | bus_dmamap_destroy(sc->sc_dmat, | 8090 | bus_dmamap_destroy(sc->sc_dmat, | |
8091 | rbd->rbd_buf[j].rb_dmap); | 8091 | rbd->rbd_buf[j].rb_dmap); | |
8092 | } | 8092 | } | |
8093 | bus_dmamap_destroy(sc->sc_dmat, | 8093 | bus_dmamap_destroy(sc->sc_dmat, | |
8094 | rbd->rbd_tmp_dmap); | 8094 | rbd->rbd_tmp_dmap); | |
8095 | goto fail; | 8095 | goto fail; | |
8096 | } | 8096 | } | |
8097 | } | 8097 | } | |
8098 | 8098 | |||
8099 | return (0); | 8099 | return (0); | |
8100 | fail: | 8100 | fail: | |
8101 | bwi_dma_mbuf_destroy(sc, ntx, 0); | 8101 | bwi_dma_mbuf_destroy(sc, ntx, 0); | |
8102 | 8102 | |||
8103 | return (error); | 8103 | return (error); | |
8104 | } | 8104 | } | |
8105 | 8105 | |||
8106 | static void | 8106 | static void | |
8107 | bwi_dma_mbuf_destroy(struct bwi_softc *sc, int ntx, int nrx) | 8107 | bwi_dma_mbuf_destroy(struct bwi_softc *sc, int ntx, int nrx) | |
8108 | { | 8108 | { | |
8109 | int i, j; | 8109 | int i, j; | |
8110 | 8110 | |||
8111 | for (i = 0; i < ntx; ++i) { | 8111 | for (i = 0; i < ntx; ++i) { | |
8112 | struct bwi_txbuf_data *tbd = &sc->sc_tx_bdata[i]; | 8112 | struct bwi_txbuf_data *tbd = &sc->sc_tx_bdata[i]; | |
8113 | 8113 | |||
8114 | for (j = 0; j < BWI_TX_NDESC; ++j) { | 8114 | for (j = 0; j < BWI_TX_NDESC; ++j) { | |
8115 | struct bwi_txbuf *tb = &tbd->tbd_buf[j]; | 8115 | struct bwi_txbuf *tb = &tbd->tbd_buf[j]; | |
8116 | 8116 | |||
8117 | if (tb->tb_mbuf != NULL) { | 8117 | if (tb->tb_mbuf != NULL) { | |
8118 | bus_dmamap_unload(sc->sc_dmat, | 8118 | bus_dmamap_unload(sc->sc_dmat, | |
8119 | tb->tb_dmap); | 8119 | tb->tb_dmap); | |
8120 | m_freem(tb->tb_mbuf); | 8120 | m_freem(tb->tb_mbuf); | |
8121 | } | 8121 | } | |
8122 | if (tb->tb_ni != NULL) | 8122 | if (tb->tb_ni != NULL) | |
8123 | ieee80211_free_node(tb->tb_ni); | 8123 | ieee80211_free_node(tb->tb_ni); | |
8124 | bus_dmamap_destroy(sc->sc_dmat, tb->tb_dmap); | 8124 | bus_dmamap_destroy(sc->sc_dmat, tb->tb_dmap); | |
8125 | } | 8125 | } | |
8126 | } | 8126 | } | |
8127 | 8127 | |||
8128 | if (nrx) { | 8128 | if (nrx) { | |
8129 | struct bwi_rxbuf_data *rbd = &sc->sc_rx_bdata; | 8129 | struct bwi_rxbuf_data *rbd = &sc->sc_rx_bdata; | |
8130 | 8130 | |||
8131 | bus_dmamap_destroy(sc->sc_dmat, rbd->rbd_tmp_dmap); | 8131 | bus_dmamap_destroy(sc->sc_dmat, rbd->rbd_tmp_dmap); | |
8132 | for (j = 0; j < BWI_RX_NDESC; ++j) { | 8132 | for (j = 0; j < BWI_RX_NDESC; ++j) { | |
8133 | struct bwi_rxbuf *rb = &rbd->rbd_buf[j]; | 8133 | struct bwi_rxbuf *rb = &rbd->rbd_buf[j]; | |
8134 | 8134 | |||
8135 | if (rb->rb_mbuf != NULL) { | 8135 | if (rb->rb_mbuf != NULL) { | |
8136 | bus_dmamap_unload(sc->sc_dmat, | 8136 | bus_dmamap_unload(sc->sc_dmat, | |
8137 | rb->rb_dmap); | 8137 | rb->rb_dmap); | |
8138 | m_freem(rb->rb_mbuf); | 8138 | m_freem(rb->rb_mbuf); | |
8139 | } | 8139 | } | |
8140 | bus_dmamap_destroy(sc->sc_dmat, rb->rb_dmap); | 8140 | bus_dmamap_destroy(sc->sc_dmat, rb->rb_dmap); | |
8141 | } | 8141 | } | |
8142 | } | 8142 | } | |
8143 | } | 8143 | } | |
8144 | 8144 | |||
8145 | static void | 8145 | static void | |
8146 | bwi_enable_intrs(struct bwi_softc *sc, uint32_t enable_intrs) | 8146 | bwi_enable_intrs(struct bwi_softc *sc, uint32_t enable_intrs) | |
8147 | { | 8147 | { | |
8148 | CSR_SETBITS_4(sc, BWI_MAC_INTR_MASK, enable_intrs); | 8148 | CSR_SETBITS_4(sc, BWI_MAC_INTR_MASK, enable_intrs); | |
8149 | } | 8149 | } | |
8150 | 8150 | |||
8151 | static void | 8151 | static void | |
8152 | bwi_disable_intrs(struct bwi_softc *sc, uint32_t disable_intrs) | 8152 | bwi_disable_intrs(struct bwi_softc *sc, uint32_t disable_intrs) | |
8153 | { | 8153 | { | |
8154 | CSR_CLRBITS_4(sc, BWI_MAC_INTR_MASK, disable_intrs); | 8154 | CSR_CLRBITS_4(sc, BWI_MAC_INTR_MASK, disable_intrs); | |
8155 | } | 8155 | } | |
8156 | 8156 | |||
8157 | static int | 8157 | static int | |
8158 | bwi_init_tx_ring32(struct bwi_softc *sc, int ring_idx) | 8158 | bwi_init_tx_ring32(struct bwi_softc *sc, int ring_idx) | |
8159 | { | 8159 | { | |
8160 | struct bwi_ring_data *rd; | 8160 | struct bwi_ring_data *rd; | |
8161 | struct bwi_txbuf_data *tbd; | 8161 | struct bwi_txbuf_data *tbd; | |
8162 | uint32_t val, addr_hi, addr_lo; | 8162 | uint32_t val, addr_hi, addr_lo; | |
8163 | 8163 | |||
8164 | KASSERT(ring_idx < BWI_TX_NRING); | 8164 | KASSERT(ring_idx < BWI_TX_NRING); | |
8165 | rd = &sc->sc_tx_rdata[ring_idx]; | 8165 | rd = &sc->sc_tx_rdata[ring_idx]; | |
8166 | tbd = &sc->sc_tx_bdata[ring_idx]; | 8166 | tbd = &sc->sc_tx_bdata[ring_idx]; | |
8167 | 8167 | |||
8168 | tbd->tbd_idx = 0; | 8168 | tbd->tbd_idx = 0; | |
8169 | tbd->tbd_used = 0; | 8169 | tbd->tbd_used = 0; | |
8170 | 8170 | |||
8171 | memset(rd->rdata_desc, 0, sizeof(struct bwi_desc32) * BWI_TX_NDESC); | 8171 | memset(rd->rdata_desc, 0, sizeof(struct bwi_desc32) * BWI_TX_NDESC); | |
8172 | bus_dmamap_sync(sc->sc_dmat, rd->rdata_dmap, 0, | 8172 | bus_dmamap_sync(sc->sc_dmat, rd->rdata_dmap, 0, | |
8173 | rd->rdata_dmap->dm_mapsize, BUS_DMASYNC_PREWRITE); | 8173 | rd->rdata_dmap->dm_mapsize, BUS_DMASYNC_PREWRITE); | |
8174 | 8174 | |||
8175 | addr_lo = __SHIFTOUT(rd->rdata_paddr, BWI_TXRX32_RINGINFO_ADDR_MASK); | 8175 | addr_lo = __SHIFTOUT(rd->rdata_paddr, BWI_TXRX32_RINGINFO_ADDR_MASK); | |
8176 | addr_hi = __SHIFTOUT(rd->rdata_paddr, BWI_TXRX32_RINGINFO_FUNC_MASK); | 8176 | addr_hi = __SHIFTOUT(rd->rdata_paddr, BWI_TXRX32_RINGINFO_FUNC_MASK); | |
8177 | 8177 | |||
8178 | val = __SHIFTIN(addr_lo, BWI_TXRX32_RINGINFO_ADDR_MASK) | | 8178 | val = __SHIFTIN(addr_lo, BWI_TXRX32_RINGINFO_ADDR_MASK) | | |
8179 | __SHIFTIN(BWI_TXRX32_RINGINFO_FUNC_TXRX, | 8179 | __SHIFTIN(BWI_TXRX32_RINGINFO_FUNC_TXRX, | |
8180 | BWI_TXRX32_RINGINFO_FUNC_MASK); | 8180 | BWI_TXRX32_RINGINFO_FUNC_MASK); | |
8181 | CSR_WRITE_4(sc, rd->rdata_txrx_ctrl + BWI_TX32_RINGINFO, val); | 8181 | CSR_WRITE_4(sc, rd->rdata_txrx_ctrl + BWI_TX32_RINGINFO, val); | |
8182 | 8182 | |||
8183 | val = __SHIFTIN(addr_hi, BWI_TXRX32_CTRL_ADDRHI_MASK) | | 8183 | val = __SHIFTIN(addr_hi, BWI_TXRX32_CTRL_ADDRHI_MASK) | | |
8184 | BWI_TXRX32_CTRL_ENABLE; | 8184 | BWI_TXRX32_CTRL_ENABLE; | |
8185 | CSR_WRITE_4(sc, rd->rdata_txrx_ctrl + BWI_TX32_CTRL, val); | 8185 | CSR_WRITE_4(sc, rd->rdata_txrx_ctrl + BWI_TX32_CTRL, val); | |
8186 | 8186 | |||
8187 | return (0); | 8187 | return (0); | |
8188 | } | 8188 | } | |
8189 | 8189 | |||
8190 | static void | 8190 | static void | |
8191 | bwi_init_rxdesc_ring32(struct bwi_softc *sc, uint32_t ctrl_base, | 8191 | bwi_init_rxdesc_ring32(struct bwi_softc *sc, uint32_t ctrl_base, | |
8192 | bus_addr_t paddr, int hdr_size, int ndesc) | 8192 | bus_addr_t paddr, int hdr_size, int ndesc) | |
8193 | { | 8193 | { | |
8194 | uint32_t val, addr_hi, addr_lo; | 8194 | uint32_t val, addr_hi, addr_lo; | |
8195 | 8195 | |||
8196 | addr_lo = __SHIFTOUT(paddr, BWI_TXRX32_RINGINFO_ADDR_MASK); | 8196 | addr_lo = __SHIFTOUT(paddr, BWI_TXRX32_RINGINFO_ADDR_MASK); | |
8197 | addr_hi = __SHIFTOUT(paddr, BWI_TXRX32_RINGINFO_FUNC_MASK); | 8197 | addr_hi = __SHIFTOUT(paddr, BWI_TXRX32_RINGINFO_FUNC_MASK); | |
8198 | 8198 | |||
8199 | val = __SHIFTIN(addr_lo, BWI_TXRX32_RINGINFO_ADDR_MASK) | | 8199 | val = __SHIFTIN(addr_lo, BWI_TXRX32_RINGINFO_ADDR_MASK) | | |
8200 | __SHIFTIN(BWI_TXRX32_RINGINFO_FUNC_TXRX, | 8200 | __SHIFTIN(BWI_TXRX32_RINGINFO_FUNC_TXRX, | |
8201 | BWI_TXRX32_RINGINFO_FUNC_MASK); | 8201 | BWI_TXRX32_RINGINFO_FUNC_MASK); | |
8202 | CSR_WRITE_4(sc, ctrl_base + BWI_RX32_RINGINFO, val); | 8202 | CSR_WRITE_4(sc, ctrl_base + BWI_RX32_RINGINFO, val); | |
8203 | 8203 | |||
8204 | val = __SHIFTIN(hdr_size, BWI_RX32_CTRL_HDRSZ_MASK) | | 8204 | val = __SHIFTIN(hdr_size, BWI_RX32_CTRL_HDRSZ_MASK) | | |
8205 | __SHIFTIN(addr_hi, BWI_TXRX32_CTRL_ADDRHI_MASK) | | 8205 | __SHIFTIN(addr_hi, BWI_TXRX32_CTRL_ADDRHI_MASK) | | |
8206 | BWI_TXRX32_CTRL_ENABLE; | 8206 | BWI_TXRX32_CTRL_ENABLE; | |
8207 | CSR_WRITE_4(sc, ctrl_base + BWI_RX32_CTRL, val); | 8207 | CSR_WRITE_4(sc, ctrl_base + BWI_RX32_CTRL, val); | |
8208 | 8208 | |||
8209 | CSR_WRITE_4(sc, ctrl_base + BWI_RX32_INDEX, | 8209 | CSR_WRITE_4(sc, ctrl_base + BWI_RX32_INDEX, | |
8210 | (ndesc - 1) * sizeof(struct bwi_desc32)); | 8210 | (ndesc - 1) * sizeof(struct bwi_desc32)); | |
8211 | } | 8211 | } | |
8212 | 8212 | |||
8213 | static int | 8213 | static int | |
8214 | bwi_init_rx_ring32(struct bwi_softc *sc) | 8214 | bwi_init_rx_ring32(struct bwi_softc *sc) | |
8215 | { | 8215 | { | |
8216 | struct bwi_ring_data *rd = &sc->sc_rx_rdata; | 8216 | struct bwi_ring_data *rd = &sc->sc_rx_rdata; | |
8217 | int i, error; | 8217 | int i, error; | |
8218 | 8218 | |||
8219 | sc->sc_rx_bdata.rbd_idx = 0; | 8219 | sc->sc_rx_bdata.rbd_idx = 0; | |
8220 | 8220 | |||
8221 | for (i = 0; i < BWI_RX_NDESC; ++i) { | 8221 | for (i = 0; i < BWI_RX_NDESC; ++i) { | |
8222 | error = bwi_newbuf(sc, i, 1); | 8222 | error = bwi_newbuf(sc, i, 1); | |
8223 | if (error) { | 8223 | if (error) { | |
8224 | aprint_error_dev(sc->sc_dev, | 8224 | aprint_error_dev(sc->sc_dev, | |
8225 | "can't allocate %dth RX buffer\n", i); | 8225 | "can't allocate %dth RX buffer\n", i); | |
8226 | return (error); | 8226 | return (error); | |
8227 | } | 8227 | } | |
8228 | } | 8228 | } | |
8229 | bus_dmamap_sync(sc->sc_dmat, rd->rdata_dmap, 0, | 8229 | bus_dmamap_sync(sc->sc_dmat, rd->rdata_dmap, 0, | |
8230 | rd->rdata_dmap->dm_mapsize, BUS_DMASYNC_PREWRITE); | 8230 | rd->rdata_dmap->dm_mapsize, BUS_DMASYNC_PREWRITE); | |
8231 | 8231 | |||
8232 | bwi_init_rxdesc_ring32(sc, rd->rdata_txrx_ctrl, rd->rdata_paddr, | 8232 | bwi_init_rxdesc_ring32(sc, rd->rdata_txrx_ctrl, rd->rdata_paddr, | |
8233 | sizeof(struct bwi_rxbuf_hdr), BWI_RX_NDESC); | 8233 | sizeof(struct bwi_rxbuf_hdr), BWI_RX_NDESC); | |
8234 | return (0); | 8234 | return (0); | |
8235 | } | 8235 | } | |
8236 | 8236 | |||
8237 | static int | 8237 | static int | |
8238 | bwi_init_txstats32(struct bwi_softc *sc) | 8238 | bwi_init_txstats32(struct bwi_softc *sc) | |
8239 | { | 8239 | { | |
8240 | struct bwi_txstats_data *st = sc->sc_txstats; | 8240 | struct bwi_txstats_data *st = sc->sc_txstats; | |
8241 | bus_addr_t stats_paddr; | 8241 | bus_addr_t stats_paddr; | |
8242 | int i; | 8242 | int i; | |
8243 | 8243 | |||
8244 | memset(st->stats, 0, BWI_TXSTATS_NDESC * sizeof(struct bwi_txstats)); | 8244 | memset(st->stats, 0, BWI_TXSTATS_NDESC * sizeof(struct bwi_txstats)); | |
8245 | bus_dmamap_sync(sc->sc_dmat, st->stats_dmap, 0, | 8245 | bus_dmamap_sync(sc->sc_dmat, st->stats_dmap, 0, | |
8246 | st->stats_dmap->dm_mapsize, BUS_DMASYNC_PREWRITE); | 8246 | st->stats_dmap->dm_mapsize, BUS_DMASYNC_PREWRITE); | |
8247 | 8247 | |||
8248 | st->stats_idx = 0; | 8248 | st->stats_idx = 0; | |
8249 | 8249 | |||
8250 | stats_paddr = st->stats_paddr; | 8250 | stats_paddr = st->stats_paddr; | |
8251 | for (i = 0; i < BWI_TXSTATS_NDESC; ++i) { | 8251 | for (i = 0; i < BWI_TXSTATS_NDESC; ++i) { | |
8252 | bwi_setup_desc32(sc, st->stats_ring, BWI_TXSTATS_NDESC, i, | 8252 | bwi_setup_desc32(sc, st->stats_ring, BWI_TXSTATS_NDESC, i, | |
8253 | stats_paddr, sizeof(struct bwi_txstats), 0); | 8253 | stats_paddr, sizeof(struct bwi_txstats), 0); | |
8254 | stats_paddr += sizeof(struct bwi_txstats); | 8254 | stats_paddr += sizeof(struct bwi_txstats); | |
8255 | } | 8255 | } | |
8256 | bus_dmamap_sync(sc->sc_dmat, st->stats_ring_dmap, 0, | 8256 | bus_dmamap_sync(sc->sc_dmat, st->stats_ring_dmap, 0, | |
8257 | st->stats_ring_dmap->dm_mapsize, BUS_DMASYNC_PREWRITE); | 8257 | st->stats_ring_dmap->dm_mapsize, BUS_DMASYNC_PREWRITE); | |
8258 | 8258 | |||
8259 | bwi_init_rxdesc_ring32(sc, st->stats_ctrl_base, | 8259 | bwi_init_rxdesc_ring32(sc, st->stats_ctrl_base, | |
8260 | st->stats_ring_paddr, 0, BWI_TXSTATS_NDESC); | 8260 | st->stats_ring_paddr, 0, BWI_TXSTATS_NDESC); | |
8261 | 8261 | |||
8262 | return (0); | 8262 | return (0); | |
8263 | } | 8263 | } | |
8264 | 8264 | |||
8265 | static void | 8265 | static void | |
8266 | bwi_setup_rx_desc32(struct bwi_softc *sc, int buf_idx, bus_addr_t paddr, | 8266 | bwi_setup_rx_desc32(struct bwi_softc *sc, int buf_idx, bus_addr_t paddr, | |
8267 | int buf_len) | 8267 | int buf_len) | |
8268 | { | 8268 | { | |
8269 | struct bwi_ring_data *rd = &sc->sc_rx_rdata; | 8269 | struct bwi_ring_data *rd = &sc->sc_rx_rdata; | |
8270 | 8270 | |||
8271 | KASSERT(buf_idx < BWI_RX_NDESC); | 8271 | KASSERT(buf_idx < BWI_RX_NDESC); | |
8272 | bwi_setup_desc32(sc, rd->rdata_desc, BWI_RX_NDESC, buf_idx, | 8272 | bwi_setup_desc32(sc, rd->rdata_desc, BWI_RX_NDESC, buf_idx, | |
8273 | paddr, buf_len, 0); | 8273 | paddr, buf_len, 0); | |
8274 | } | 8274 | } | |
8275 | 8275 | |||
8276 | static void | 8276 | static void | |
8277 | bwi_setup_tx_desc32(struct bwi_softc *sc, struct bwi_ring_data *rd, | 8277 | bwi_setup_tx_desc32(struct bwi_softc *sc, struct bwi_ring_data *rd, | |
8278 | int buf_idx, bus_addr_t paddr, int buf_len) | 8278 | int buf_idx, bus_addr_t paddr, int buf_len) | |
8279 | { | 8279 | { | |
8280 | KASSERT(buf_idx < BWI_TX_NDESC); | 8280 | KASSERT(buf_idx < BWI_TX_NDESC); | |
8281 | bwi_setup_desc32(sc, rd->rdata_desc, BWI_TX_NDESC, buf_idx, | 8281 | bwi_setup_desc32(sc, rd->rdata_desc, BWI_TX_NDESC, buf_idx, | |
8282 | paddr, buf_len, 1); | 8282 | paddr, buf_len, 1); | |
8283 | } | 8283 | } | |
8284 | static int | 8284 | static int | |
8285 | bwi_init_tx_ring64(struct bwi_softc *sc, int ring_idx) | 8285 | bwi_init_tx_ring64(struct bwi_softc *sc, int ring_idx) | |
8286 | { | 8286 | { | |
8287 | /* TODO: 64 */ | 8287 | /* TODO: 64 */ | |
8288 | return (EOPNOTSUPP); | 8288 | return (EOPNOTSUPP); | |
8289 | } | 8289 | } | |
8290 | 8290 | |||
8291 | static int | 8291 | static int | |
8292 | bwi_init_rx_ring64(struct bwi_softc *sc) | 8292 | bwi_init_rx_ring64(struct bwi_softc *sc) | |
8293 | { | 8293 | { | |
8294 | /* TODO: 64 */ | 8294 | /* TODO: 64 */ | |
8295 | return (EOPNOTSUPP); | 8295 | return (EOPNOTSUPP); | |
8296 | } | 8296 | } | |
8297 | 8297 | |||
8298 | static int | 8298 | static int | |
8299 | bwi_init_txstats64(struct bwi_softc *sc) | 8299 | bwi_init_txstats64(struct bwi_softc *sc) | |
8300 | { | 8300 | { | |
8301 | /* TODO: 64 */ | 8301 | /* TODO: 64 */ | |
8302 | return (EOPNOTSUPP); | 8302 | return (EOPNOTSUPP); | |
8303 | } | 8303 | } | |
8304 | 8304 | |||
8305 | static void | 8305 | static void | |
8306 | bwi_setup_rx_desc64(struct bwi_softc *sc, int buf_idx, bus_addr_t paddr, | 8306 | bwi_setup_rx_desc64(struct bwi_softc *sc, int buf_idx, bus_addr_t paddr, | |
8307 | int buf_len) | 8307 | int buf_len) | |
8308 | { | 8308 | { | |
8309 | /* TODO: 64 */ | 8309 | /* TODO: 64 */ | |
8310 | } | 8310 | } | |
8311 | 8311 | |||
8312 | static void | 8312 | static void | |
8313 | bwi_setup_tx_desc64(struct bwi_softc *sc, struct bwi_ring_data *rd, | 8313 | bwi_setup_tx_desc64(struct bwi_softc *sc, struct bwi_ring_data *rd, | |
8314 | int buf_idx, bus_addr_t paddr, int buf_len) | 8314 | int buf_idx, bus_addr_t paddr, int buf_len) | |
8315 | { | 8315 | { | |
8316 | /* TODO: 64 */ | 8316 | /* TODO: 64 */ | |
8317 | } | 8317 | } | |
8318 | 8318 | |||
8319 | static int | 8319 | static int | |
8320 | bwi_newbuf(struct bwi_softc *sc, int buf_idx, int init) | 8320 | bwi_newbuf(struct bwi_softc *sc, int buf_idx, int init) | |
8321 | { | 8321 | { | |
8322 | struct bwi_rxbuf_data *rbd = &sc->sc_rx_bdata; | 8322 | struct bwi_rxbuf_data *rbd = &sc->sc_rx_bdata; | |
8323 | struct bwi_rxbuf *rxbuf = &rbd->rbd_buf[buf_idx]; | 8323 | struct bwi_rxbuf *rxbuf = &rbd->rbd_buf[buf_idx]; | |
8324 | struct bwi_rxbuf_hdr *hdr; | 8324 | struct bwi_rxbuf_hdr *hdr; | |
8325 | bus_dmamap_t map; | 8325 | bus_dmamap_t map; | |
8326 | bus_addr_t paddr; | 8326 | bus_addr_t paddr; | |
8327 | struct mbuf *m; | 8327 | struct mbuf *m; | |
8328 | int error; | 8328 | int error; | |
8329 | 8329 | |||
8330 | KASSERT(buf_idx < BWI_RX_NDESC); | 8330 | KASSERT(buf_idx < BWI_RX_NDESC); | |
8331 | 8331 | |||
8332 | MGETHDR(m, init ? M_WAITOK : M_DONTWAIT, MT_DATA); | 8332 | MGETHDR(m, init ? M_WAITOK : M_DONTWAIT, MT_DATA); | |
8333 | if (m == NULL) | 8333 | if (m == NULL) | |
8334 | return (ENOBUFS); | 8334 | return (ENOBUFS); | |
8335 | MCLGET(m, init ? M_WAITOK : M_DONTWAIT); | 8335 | MCLGET(m, init ? M_WAITOK : M_DONTWAIT); | |
8336 | if ((m->m_flags & M_EXT) == 0) { | 8336 | if ((m->m_flags & M_EXT) == 0) { | |
8337 | error = ENOBUFS; | 8337 | error = ENOBUFS; | |
8338 | 8338 | |||
8339 | /* | 8339 | /* | |
8340 | * If the NIC is up and running, we need to: | 8340 | * If the NIC is up and running, we need to: | |
8341 | * - Clear RX buffer's header. | 8341 | * - Clear RX buffer's header. | |
8342 | * - Restore RX descriptor settings. | 8342 | * - Restore RX descriptor settings. | |
8343 | */ | 8343 | */ | |
8344 | if (init) | 8344 | if (init) | |
8345 | return error; | 8345 | return error; | |
8346 | else | 8346 | else | |
8347 | goto back; | 8347 | goto back; | |
8348 | } | 8348 | } | |
8349 | m->m_len = m->m_pkthdr.len = MCLBYTES; | 8349 | m->m_len = m->m_pkthdr.len = MCLBYTES; | |
8350 | 8350 | |||
8351 | /* | 8351 | /* | |
8352 | * Try to load RX buf into temporary DMA map | 8352 | * Try to load RX buf into temporary DMA map | |
8353 | */ | 8353 | */ | |
8354 | error = bus_dmamap_load_mbuf(sc->sc_dmat, rbd->rbd_tmp_dmap, m, | 8354 | error = bus_dmamap_load_mbuf(sc->sc_dmat, rbd->rbd_tmp_dmap, m, | |
8355 | init ? BUS_DMA_WAITOK : BUS_DMA_NOWAIT); | 8355 | init ? BUS_DMA_WAITOK : BUS_DMA_NOWAIT); | |
8356 | if (error) { | 8356 | if (error) { | |
8357 | m_freem(m); | 8357 | m_freem(m); | |
8358 | 8358 | |||
8359 | /* | 8359 | /* | |
8360 | * See the comment above | 8360 | * See the comment above | |
8361 | */ | 8361 | */ | |
8362 | if (init) | 8362 | if (init) | |
8363 | return error; | 8363 | return error; | |
8364 | else | 8364 | else | |
8365 | goto back; | 8365 | goto back; | |
8366 | } | 8366 | } | |
8367 | 8367 | |||
8368 | if (!init) | 8368 | if (!init) | |
8369 | bus_dmamap_unload(sc->sc_dmat, rxbuf->rb_dmap); | 8369 | bus_dmamap_unload(sc->sc_dmat, rxbuf->rb_dmap); | |
8370 | rxbuf->rb_mbuf = m; | 8370 | rxbuf->rb_mbuf = m; | |
8371 | 8371 | |||
8372 | /* | 8372 | /* | |
8373 | * Swap RX buf's DMA map with the loaded temporary one | 8373 | * Swap RX buf's DMA map with the loaded temporary one | |
8374 | */ | 8374 | */ | |
8375 | map = rxbuf->rb_dmap; | 8375 | map = rxbuf->rb_dmap; | |
8376 | rxbuf->rb_dmap = rbd->rbd_tmp_dmap; | 8376 | rxbuf->rb_dmap = rbd->rbd_tmp_dmap; | |
8377 | rbd->rbd_tmp_dmap = map; | 8377 | rbd->rbd_tmp_dmap = map; | |
8378 | paddr = rxbuf->rb_dmap->dm_segs[0].ds_addr; | 8378 | paddr = rxbuf->rb_dmap->dm_segs[0].ds_addr; | |
8379 | rxbuf->rb_paddr = paddr; | 8379 | rxbuf->rb_paddr = paddr; | |
8380 | 8380 | |||
8381 | back: | 8381 | back: | |
8382 | /* | 8382 | /* | |
8383 | * Clear RX buf header | 8383 | * Clear RX buf header | |
8384 | */ | 8384 | */ | |
8385 | hdr = mtod(rxbuf->rb_mbuf, struct bwi_rxbuf_hdr *); | 8385 | hdr = mtod(rxbuf->rb_mbuf, struct bwi_rxbuf_hdr *); | |
8386 | memset(hdr, 0, sizeof(*hdr)); | 8386 | memset(hdr, 0, sizeof(*hdr)); | |
8387 | bus_dmamap_sync(sc->sc_dmat, rxbuf->rb_dmap, 0, | 8387 | bus_dmamap_sync(sc->sc_dmat, rxbuf->rb_dmap, 0, | |
8388 | rxbuf->rb_dmap->dm_mapsize, BUS_DMASYNC_PREWRITE); | 8388 | rxbuf->rb_dmap->dm_mapsize, BUS_DMASYNC_PREWRITE); | |
8389 | 8389 | |||
8390 | /* | 8390 | /* | |
8391 | * Setup RX buf descriptor | 8391 | * Setup RX buf descriptor | |
8392 | */ | 8392 | */ | |
8393 | (sc->sc_setup_rxdesc)(sc, buf_idx, rxbuf->rb_paddr, | 8393 | (sc->sc_setup_rxdesc)(sc, buf_idx, rxbuf->rb_paddr, | |
8394 | rxbuf->rb_mbuf->m_len - sizeof(*hdr)); | 8394 | rxbuf->rb_mbuf->m_len - sizeof(*hdr)); | |
8395 | return error; | 8395 | return error; | |
8396 | } | 8396 | } | |
8397 | 8397 | |||
8398 | static void | 8398 | static void | |
8399 | bwi_set_addr_filter(struct bwi_softc *sc, uint16_t addr_ofs, | 8399 | bwi_set_addr_filter(struct bwi_softc *sc, uint16_t addr_ofs, | |
8400 | const uint8_t *addr) | 8400 | const uint8_t *addr) | |
8401 | { | 8401 | { | |
8402 | int i; | 8402 | int i; | |
8403 | 8403 | |||
8404 | CSR_WRITE_2(sc, BWI_ADDR_FILTER_CTRL, | 8404 | CSR_WRITE_2(sc, BWI_ADDR_FILTER_CTRL, | |
8405 | BWI_ADDR_FILTER_CTRL_SET | addr_ofs); | 8405 | BWI_ADDR_FILTER_CTRL_SET | addr_ofs); | |
8406 | 8406 | |||
8407 | for (i = 0; i < (IEEE80211_ADDR_LEN / 2); ++i) { | 8407 | for (i = 0; i < (IEEE80211_ADDR_LEN / 2); ++i) { | |
8408 | uint16_t addr_val; | 8408 | uint16_t addr_val; | |
8409 | 8409 | |||
8410 | addr_val = (uint16_t)addr[i * 2] | | 8410 | addr_val = (uint16_t)addr[i * 2] | | |
8411 | (((uint16_t)addr[(i * 2) + 1]) << 8); | 8411 | (((uint16_t)addr[(i * 2) + 1]) << 8); | |
8412 | CSR_WRITE_2(sc, BWI_ADDR_FILTER_DATA, addr_val); | 8412 | CSR_WRITE_2(sc, BWI_ADDR_FILTER_DATA, addr_val); | |
8413 | } | 8413 | } | |
8414 | } | 8414 | } | |
8415 | 8415 | |||
8416 | static int | 8416 | static int | |
8417 | bwi_set_chan(struct bwi_softc *sc, struct ieee80211_channel *c) | 8417 | bwi_set_chan(struct bwi_softc *sc, struct ieee80211_channel *c) | |
8418 | { | 8418 | { | |
8419 | struct ieee80211com *ic = &sc->sc_ic; | 8419 | struct ieee80211com *ic = &sc->sc_ic; | |
8420 | struct bwi_mac *mac; | 8420 | struct bwi_mac *mac; | |
8421 | /* uint16_t flags; */ /* [TRC: XXX See below.] */ | 8421 | /* uint16_t flags; */ /* [TRC: XXX See below.] */ | |
8422 | uint chan; | 8422 | uint chan; | |
8423 | 8423 | |||
8424 | KASSERT(sc->sc_cur_regwin->rw_type == BWI_REGWIN_T_MAC); | 8424 | KASSERT(sc->sc_cur_regwin->rw_type == BWI_REGWIN_T_MAC); | |
8425 | mac = (struct bwi_mac *)sc->sc_cur_regwin; | 8425 | mac = (struct bwi_mac *)sc->sc_cur_regwin; | |
8426 | 8426 | |||
8427 | chan = ieee80211_chan2ieee(ic, c); | 8427 | chan = ieee80211_chan2ieee(ic, c); | |
8428 | 8428 | |||
8429 | bwi_rf_set_chan(mac, chan, 0); | 8429 | bwi_rf_set_chan(mac, chan, 0); | |
8430 | 8430 | |||
8431 | /* [TRC: XXX DragonFlyBSD sets up radio tap channel frequency | 8431 | /* [TRC: XXX DragonFlyBSD sets up radio tap channel frequency | |
8432 | and flags here. OpenBSD does not, and appears to do so | 8432 | and flags here. OpenBSD does not, and appears to do so | |
8433 | later (in bwi_rxeof and bwi_encap).] */ | 8433 | later (in bwi_rxeof and bwi_encap).] */ | |
8434 | 8434 | |||
8435 | return (0); | 8435 | return (0); | |
8436 | } | 8436 | } | |
8437 | 8437 | |||
8438 | static void | 8438 | static void | |
8439 | bwi_next_scan(void *xsc) | 8439 | bwi_next_scan(void *xsc) | |
8440 | { | 8440 | { | |
8441 | struct bwi_softc *sc = xsc; | 8441 | struct bwi_softc *sc = xsc; | |
8442 | struct ieee80211com *ic = &sc->sc_ic; | 8442 | struct ieee80211com *ic = &sc->sc_ic; | |
8443 | int s; | 8443 | int s; | |
8444 | 8444 | |||
8445 | s = splnet(); | 8445 | s = splnet(); | |
8446 | 8446 | |||
8447 | if (ic->ic_state == IEEE80211_S_SCAN) | 8447 | if (ic->ic_state == IEEE80211_S_SCAN) | |
8448 | ieee80211_next_scan(ic); | 8448 | ieee80211_next_scan(ic); | |
8449 | 8449 | |||
8450 | splx(s); | 8450 | splx(s); | |
8451 | } | 8451 | } | |
8452 | 8452 | |||
8453 | static int | 8453 | static int | |
8454 | bwi_rxeof(struct bwi_softc *sc, int end_idx) | 8454 | bwi_rxeof(struct bwi_softc *sc, int end_idx) | |
8455 | { | 8455 | { | |
8456 | struct bwi_ring_data *rd = &sc->sc_rx_rdata; | 8456 | struct bwi_ring_data *rd = &sc->sc_rx_rdata; | |
8457 | struct bwi_rxbuf_data *rbd = &sc->sc_rx_bdata; | 8457 | struct bwi_rxbuf_data *rbd = &sc->sc_rx_bdata; | |
8458 | struct ieee80211com *ic = &sc->sc_ic; | 8458 | struct ieee80211com *ic = &sc->sc_ic; | |
8459 | struct ifnet *ifp = &sc->sc_if; | 8459 | struct ifnet *ifp = &sc->sc_if; | |
8460 | int s, idx, rx_data = 0; | 8460 | int s, idx, rx_data = 0; | |
8461 | 8461 | |||
8462 | idx = rbd->rbd_idx; | 8462 | idx = rbd->rbd_idx; | |
8463 | while (idx != end_idx) { | 8463 | while (idx != end_idx) { | |
8464 | struct bwi_rxbuf *rb = &rbd->rbd_buf[idx]; | 8464 | struct bwi_rxbuf *rb = &rbd->rbd_buf[idx]; | |
8465 | struct bwi_rxbuf_hdr *hdr; | 8465 | struct bwi_rxbuf_hdr *hdr; | |
8466 | struct ieee80211_frame_min *wh; | 8466 | struct ieee80211_frame_min *wh; | |
8467 | struct ieee80211_node *ni; | 8467 | struct ieee80211_node *ni; | |
8468 | struct mbuf *m; | 8468 | struct mbuf *m; | |
8469 | const void *plcp; | 8469 | const void *plcp; | |
8470 | uint16_t flags2; | 8470 | uint16_t flags2; | |
8471 | int buflen, wh_ofs, hdr_extra, rssi, type, rate; | 8471 | int buflen, wh_ofs, hdr_extra, rssi, type, rate; | |
8472 | 8472 | |||
8473 | m = rb->rb_mbuf; | 8473 | m = rb->rb_mbuf; | |
8474 | bus_dmamap_sync(sc->sc_dmat, rb->rb_dmap, 0, | 8474 | bus_dmamap_sync(sc->sc_dmat, rb->rb_dmap, 0, | |
8475 | rb->rb_dmap->dm_mapsize, BUS_DMASYNC_POSTREAD); | 8475 | rb->rb_dmap->dm_mapsize, BUS_DMASYNC_POSTREAD); | |
8476 | 8476 | |||
8477 | if (bwi_newbuf(sc, idx, 0)) { | 8477 | if (bwi_newbuf(sc, idx, 0)) { | |
8478 | ifp->if_ierrors++; | 8478 | if_statinc(ifp, if_ierrors); | |
8479 | goto next; | 8479 | goto next; | |
8480 | } | 8480 | } | |
8481 | 8481 | |||
8482 | hdr = mtod(m, struct bwi_rxbuf_hdr *); | 8482 | hdr = mtod(m, struct bwi_rxbuf_hdr *); | |
8483 | flags2 = le16toh(hdr->rxh_flags2); | 8483 | flags2 = le16toh(hdr->rxh_flags2); | |
8484 | 8484 | |||
8485 | hdr_extra = 0; | 8485 | hdr_extra = 0; | |
8486 | if (flags2 & BWI_RXH_F2_TYPE2FRAME) | 8486 | if (flags2 & BWI_RXH_F2_TYPE2FRAME) | |
8487 | hdr_extra = 2; | 8487 | hdr_extra = 2; | |
8488 | wh_ofs = hdr_extra + 6; /* XXX magic number */ | 8488 | wh_ofs = hdr_extra + 6; /* XXX magic number */ | |
8489 | 8489 | |||
8490 | buflen = le16toh(hdr->rxh_buflen); | 8490 | buflen = le16toh(hdr->rxh_buflen); | |
8491 | if (buflen < BWI_FRAME_MIN_LEN(wh_ofs)) { | 8491 | if (buflen < BWI_FRAME_MIN_LEN(wh_ofs)) { | |
8492 | aprint_error_dev(sc->sc_dev, "short frame %d," | 8492 | aprint_error_dev(sc->sc_dev, "short frame %d," | |
8493 | " hdr_extra %d\n", buflen, hdr_extra); | 8493 | " hdr_extra %d\n", buflen, hdr_extra); | |
8494 | ifp->if_ierrors++; | 8494 | if_statinc(ifp, if_ierrors); | |
8495 | m_freem(m); | 8495 | m_freem(m); | |
8496 | goto next; | 8496 | goto next; | |
8497 | } | 8497 | } | |
8498 | 8498 | |||
8499 | plcp = ((const uint8_t *)(hdr + 1) + hdr_extra); | 8499 | plcp = ((const uint8_t *)(hdr + 1) + hdr_extra); | |
8500 | rssi = bwi_calc_rssi(sc, hdr); | 8500 | rssi = bwi_calc_rssi(sc, hdr); | |
8501 | 8501 | |||
8502 | m_set_rcvif(m, ifp); | 8502 | m_set_rcvif(m, ifp); | |
8503 | m->m_len = m->m_pkthdr.len = buflen + sizeof(*hdr); | 8503 | m->m_len = m->m_pkthdr.len = buflen + sizeof(*hdr); | |
8504 | m_adj(m, sizeof(*hdr) + wh_ofs); | 8504 | m_adj(m, sizeof(*hdr) + wh_ofs); | |
8505 | 8505 | |||
8506 | if (htole16(hdr->rxh_flags1) & BWI_RXH_F1_OFDM) | 8506 | if (htole16(hdr->rxh_flags1) & BWI_RXH_F1_OFDM) | |
8507 | rate = bwi_ofdm_plcp2rate(plcp); | 8507 | rate = bwi_ofdm_plcp2rate(plcp); | |
8508 | else | 8508 | else | |
8509 | rate = bwi_ds_plcp2rate(plcp); | 8509 | rate = bwi_ds_plcp2rate(plcp); | |
8510 | 8510 | |||
8511 | s = splnet(); | 8511 | s = splnet(); | |
8512 | 8512 | |||
8513 | /* RX radio tap */ | 8513 | /* RX radio tap */ | |
8514 | if (sc->sc_drvbpf != NULL) { | 8514 | if (sc->sc_drvbpf != NULL) { | |
8515 | struct mbuf mb; | 8515 | struct mbuf mb; | |
8516 | struct bwi_rx_radiotap_hdr *tap = &sc->sc_rxtap; | 8516 | struct bwi_rx_radiotap_hdr *tap = &sc->sc_rxtap; | |
8517 | 8517 | |||
8518 | tap->wr_tsf = hdr->rxh_tsf; | 8518 | tap->wr_tsf = hdr->rxh_tsf; | |
8519 | tap->wr_flags = 0; | 8519 | tap->wr_flags = 0; | |
8520 | tap->wr_rate = rate; | 8520 | tap->wr_rate = rate; | |
8521 | tap->wr_chan_freq = | 8521 | tap->wr_chan_freq = | |
8522 | htole16(ic->ic_bss->ni_chan->ic_freq); | 8522 | htole16(ic->ic_bss->ni_chan->ic_freq); | |
8523 | tap->wr_chan_flags = | 8523 | tap->wr_chan_flags = | |
8524 | htole16(ic->ic_bss->ni_chan->ic_flags); | 8524 | htole16(ic->ic_bss->ni_chan->ic_flags); | |
8525 | tap->wr_antsignal = rssi; | 8525 | tap->wr_antsignal = rssi; | |
8526 | tap->wr_antnoise = BWI_NOISE_FLOOR; | 8526 | tap->wr_antnoise = BWI_NOISE_FLOOR; | |
8527 | 8527 | |||
8528 | mb.m_data = (void *)tap; | 8528 | mb.m_data = (void *)tap; | |
8529 | mb.m_len = sc->sc_rxtap_len; | 8529 | mb.m_len = sc->sc_rxtap_len; | |
8530 | mb.m_next = m; | 8530 | mb.m_next = m; | |
8531 | mb.m_nextpkt = NULL; | 8531 | mb.m_nextpkt = NULL; | |
8532 | mb.m_owner = NULL; | 8532 | mb.m_owner = NULL; | |
8533 | mb.m_type = 0; | 8533 | mb.m_type = 0; | |
8534 | mb.m_flags = 0; | 8534 | mb.m_flags = 0; | |
8535 | bpf_mtap3(sc->sc_drvbpf, &mb, BPF_D_IN); | 8535 | bpf_mtap3(sc->sc_drvbpf, &mb, BPF_D_IN); | |
8536 | } | 8536 | } | |
8537 | 8537 | |||
8538 | m_adj(m, -IEEE80211_CRC_LEN); | 8538 | m_adj(m, -IEEE80211_CRC_LEN); | |
8539 | 8539 | |||
8540 | wh = mtod(m, struct ieee80211_frame_min *); | 8540 | wh = mtod(m, struct ieee80211_frame_min *); | |
8541 | ni = ieee80211_find_rxnode(ic, wh); | 8541 | ni = ieee80211_find_rxnode(ic, wh); | |
8542 | type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; | 8542 | type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; | |
8543 | 8543 | |||
8544 | ieee80211_input(ic, m, ni, hdr->rxh_rssi, | 8544 | ieee80211_input(ic, m, ni, hdr->rxh_rssi, | |
8545 | le16toh(hdr->rxh_tsf)); | 8545 | le16toh(hdr->rxh_tsf)); | |
8546 | 8546 | |||
8547 | ieee80211_free_node(ni); | 8547 | ieee80211_free_node(ni); | |
8548 | 8548 | |||
8549 | if (type == IEEE80211_FC0_TYPE_DATA) { | 8549 | if (type == IEEE80211_FC0_TYPE_DATA) { | |
8550 | rx_data = 1; | 8550 | rx_data = 1; | |
8551 | sc->sc_rx_rate = rate; | 8551 | sc->sc_rx_rate = rate; | |
8552 | } | 8552 | } | |
8553 | 8553 | |||
8554 | splx(s); | 8554 | splx(s); | |
8555 | next: | 8555 | next: | |
8556 | idx = (idx + 1) % BWI_RX_NDESC; | 8556 | idx = (idx + 1) % BWI_RX_NDESC; | |
8557 | } | 8557 | } | |
8558 | 8558 | |||
8559 | rbd->rbd_idx = idx; | 8559 | rbd->rbd_idx = idx; | |
8560 | bus_dmamap_sync(sc->sc_dmat, rd->rdata_dmap, 0, | 8560 | bus_dmamap_sync(sc->sc_dmat, rd->rdata_dmap, 0, | |
8561 | rd->rdata_dmap->dm_mapsize, BUS_DMASYNC_PREWRITE); | 8561 | rd->rdata_dmap->dm_mapsize, BUS_DMASYNC_PREWRITE); | |
8562 | 8562 | |||
8563 | return (rx_data); | 8563 | return (rx_data); | |
8564 | } | 8564 | } | |
8565 | 8565 | |||
8566 | static int | 8566 | static int | |
8567 | bwi_rxeof32(struct bwi_softc *sc) | 8567 | bwi_rxeof32(struct bwi_softc *sc) | |
8568 | { | 8568 | { | |
8569 | uint32_t val, rx_ctrl; | 8569 | uint32_t val, rx_ctrl; | |
8570 | int end_idx, rx_data; | 8570 | int end_idx, rx_data; | |
8571 | 8571 | |||
8572 | rx_ctrl = sc->sc_rx_rdata.rdata_txrx_ctrl; | 8572 | rx_ctrl = sc->sc_rx_rdata.rdata_txrx_ctrl; | |
8573 | 8573 | |||
8574 | val = CSR_READ_4(sc, rx_ctrl + BWI_RX32_STATUS); | 8574 | val = CSR_READ_4(sc, rx_ctrl + BWI_RX32_STATUS); | |
8575 | end_idx = __SHIFTOUT(val, BWI_RX32_STATUS_INDEX_MASK) / | 8575 | end_idx = __SHIFTOUT(val, BWI_RX32_STATUS_INDEX_MASK) / | |
8576 | sizeof(struct bwi_desc32); | 8576 | sizeof(struct bwi_desc32); | |
8577 | 8577 | |||
8578 | rx_data = bwi_rxeof(sc, end_idx); | 8578 | rx_data = bwi_rxeof(sc, end_idx); | |
8579 | 8579 | |||
8580 | CSR_WRITE_4(sc, rx_ctrl + BWI_RX32_INDEX, | 8580 | CSR_WRITE_4(sc, rx_ctrl + BWI_RX32_INDEX, | |
8581 | end_idx * sizeof(struct bwi_desc32)); | 8581 | end_idx * sizeof(struct bwi_desc32)); | |
8582 | 8582 | |||
8583 | return (rx_data); | 8583 | return (rx_data); | |
8584 | } | 8584 | } | |
8585 | 8585 | |||
8586 | static int | 8586 | static int | |
8587 | bwi_rxeof64(struct bwi_softc *sc) | 8587 | bwi_rxeof64(struct bwi_softc *sc) | |
8588 | { | 8588 | { | |
8589 | /* TODO: 64 */ | 8589 | /* TODO: 64 */ | |
8590 | return (0); | 8590 | return (0); | |
8591 | } | 8591 | } | |
8592 | 8592 | |||
8593 | static void | 8593 | static void | |
8594 | bwi_reset_rx_ring32(struct bwi_softc *sc, uint32_t rx_ctrl) | 8594 | bwi_reset_rx_ring32(struct bwi_softc *sc, uint32_t rx_ctrl) | |
8595 | { | 8595 | { | |
8596 | int i; | 8596 | int i; | |
8597 | 8597 | |||
8598 | CSR_WRITE_4(sc, rx_ctrl + BWI_RX32_CTRL, 0); | 8598 | CSR_WRITE_4(sc, rx_ctrl + BWI_RX32_CTRL, 0); | |
8599 | 8599 | |||
8600 | #define NRETRY 10 | 8600 | #define NRETRY 10 | |
8601 | for (i = 0; i < NRETRY; ++i) { | 8601 | for (i = 0; i < NRETRY; ++i) { | |
8602 | uint32_t status; | 8602 | uint32_t status; | |
8603 | 8603 | |||
8604 | status = CSR_READ_4(sc, rx_ctrl + BWI_RX32_STATUS); | 8604 | status = CSR_READ_4(sc, rx_ctrl + BWI_RX32_STATUS); | |
8605 | if (__SHIFTOUT(status, BWI_RX32_STATUS_STATE_MASK) == | 8605 | if (__SHIFTOUT(status, BWI_RX32_STATUS_STATE_MASK) == | |
8606 | BWI_RX32_STATUS_STATE_DISABLED) | 8606 | BWI_RX32_STATUS_STATE_DISABLED) | |
8607 | break; | 8607 | break; | |
8608 | 8608 | |||
8609 | DELAY(1000); | 8609 | DELAY(1000); | |
8610 | } | 8610 | } | |
8611 | if (i == NRETRY) | 8611 | if (i == NRETRY) | |
8612 | aprint_error_dev(sc->sc_dev, "reset rx ring timedout\n"); | 8612 | aprint_error_dev(sc->sc_dev, "reset rx ring timedout\n"); | |
8613 | #undef NRETRY | 8613 | #undef NRETRY | |
8614 | 8614 | |||
8615 | CSR_WRITE_4(sc, rx_ctrl + BWI_RX32_RINGINFO, 0); | 8615 | CSR_WRITE_4(sc, rx_ctrl + BWI_RX32_RINGINFO, 0); | |
8616 | } | 8616 | } | |
8617 | 8617 | |||
8618 | static void | 8618 | static void | |
8619 | bwi_free_txstats32(struct bwi_softc *sc) | 8619 | bwi_free_txstats32(struct bwi_softc *sc) | |
8620 | { | 8620 | { | |
8621 | bwi_reset_rx_ring32(sc, sc->sc_txstats->stats_ctrl_base); | 8621 | bwi_reset_rx_ring32(sc, sc->sc_txstats->stats_ctrl_base); | |
8622 | } | 8622 | } | |
8623 | 8623 | |||
8624 | static void | 8624 | static void | |
8625 | bwi_free_rx_ring32(struct bwi_softc *sc) | 8625 | bwi_free_rx_ring32(struct bwi_softc *sc) | |
8626 | { | 8626 | { | |
8627 | struct bwi_ring_data *rd = &sc->sc_rx_rdata; | 8627 | struct bwi_ring_data *rd = &sc->sc_rx_rdata; | |
8628 | struct bwi_rxbuf_data *rbd = &sc->sc_rx_bdata; | 8628 | struct bwi_rxbuf_data *rbd = &sc->sc_rx_bdata; | |
8629 | int i; | 8629 | int i; | |
8630 | 8630 | |||
8631 | bwi_reset_rx_ring32(sc, rd->rdata_txrx_ctrl); | 8631 | bwi_reset_rx_ring32(sc, rd->rdata_txrx_ctrl); | |
8632 | 8632 | |||
8633 | for (i = 0; i < BWI_RX_NDESC; ++i) { | 8633 | for (i = 0; i < BWI_RX_NDESC; ++i) { | |
8634 | struct bwi_rxbuf *rb = &rbd->rbd_buf[i]; | 8634 | struct bwi_rxbuf *rb = &rbd->rbd_buf[i]; | |
8635 | 8635 | |||
8636 | if (rb->rb_mbuf != NULL) { | 8636 | if (rb->rb_mbuf != NULL) { | |
8637 | bus_dmamap_unload(sc->sc_dmat, rb->rb_dmap); | 8637 | bus_dmamap_unload(sc->sc_dmat, rb->rb_dmap); | |
8638 | m_freem(rb->rb_mbuf); | 8638 | m_freem(rb->rb_mbuf); | |
8639 | rb->rb_mbuf = NULL; | 8639 | rb->rb_mbuf = NULL; | |
8640 | } | 8640 | } | |
8641 | } | 8641 | } | |
8642 | } | 8642 | } | |
8643 | 8643 | |||
8644 | static void | 8644 | static void | |
8645 | bwi_free_tx_ring32(struct bwi_softc *sc, int ring_idx) | 8645 | bwi_free_tx_ring32(struct bwi_softc *sc, int ring_idx) | |
8646 | { | 8646 | { | |
8647 | struct bwi_ring_data *rd; | 8647 | struct bwi_ring_data *rd; | |
8648 | struct bwi_txbuf_data *tbd; | 8648 | struct bwi_txbuf_data *tbd; | |
8649 | uint32_t state, val; | 8649 | uint32_t state, val; | |
8650 | int i; | 8650 | int i; | |
8651 | 8651 | |||
8652 | KASSERT(ring_idx < BWI_TX_NRING); | 8652 | KASSERT(ring_idx < BWI_TX_NRING); | |
8653 | rd = &sc->sc_tx_rdata[ring_idx]; | 8653 | rd = &sc->sc_tx_rdata[ring_idx]; | |
8654 | tbd = &sc->sc_tx_bdata[ring_idx]; | 8654 | tbd = &sc->sc_tx_bdata[ring_idx]; | |
8655 | 8655 | |||
8656 | #define NRETRY 10 | 8656 | #define NRETRY 10 | |
8657 | for (i = 0; i < NRETRY; ++i) { | 8657 | for (i = 0; i < NRETRY; ++i) { | |
8658 | val = CSR_READ_4(sc, rd->rdata_txrx_ctrl + BWI_TX32_STATUS); | 8658 | val = CSR_READ_4(sc, rd->rdata_txrx_ctrl + BWI_TX32_STATUS); | |
8659 | state = __SHIFTOUT(val, BWI_TX32_STATUS_STATE_MASK); | 8659 | state = __SHIFTOUT(val, BWI_TX32_STATUS_STATE_MASK); | |
8660 | if (state == BWI_TX32_STATUS_STATE_DISABLED || | 8660 | if (state == BWI_TX32_STATUS_STATE_DISABLED || | |
8661 | state == BWI_TX32_STATUS_STATE_IDLE || | 8661 | state == BWI_TX32_STATUS_STATE_IDLE || | |
8662 | state == BWI_TX32_STATUS_STATE_STOPPED) | 8662 | state == BWI_TX32_STATUS_STATE_STOPPED) | |
8663 | break; | 8663 | break; | |
8664 | 8664 | |||
8665 | DELAY(1000); | 8665 | DELAY(1000); | |
8666 | } | 8666 | } | |
8667 | if (i == NRETRY) | 8667 | if (i == NRETRY) | |
8668 | aprint_error_dev(sc->sc_dev, | 8668 | aprint_error_dev(sc->sc_dev, | |
8669 | "wait for TX ring(%d) stable timed out\n", ring_idx); | 8669 | "wait for TX ring(%d) stable timed out\n", ring_idx); | |
8670 | 8670 | |||
8671 | CSR_WRITE_4(sc, rd->rdata_txrx_ctrl + BWI_TX32_CTRL, 0); | 8671 | CSR_WRITE_4(sc, rd->rdata_txrx_ctrl + BWI_TX32_CTRL, 0); | |
8672 | for (i = 0; i < NRETRY; ++i) { | 8672 | for (i = 0; i < NRETRY; ++i) { | |
8673 | val = CSR_READ_4(sc, rd->rdata_txrx_ctrl + BWI_TX32_STATUS); | 8673 | val = CSR_READ_4(sc, rd->rdata_txrx_ctrl + BWI_TX32_STATUS); | |
8674 | state = __SHIFTOUT(val, BWI_TX32_STATUS_STATE_MASK); | 8674 | state = __SHIFTOUT(val, BWI_TX32_STATUS_STATE_MASK); | |
8675 | if (state == BWI_TX32_STATUS_STATE_DISABLED) | 8675 | if (state == BWI_TX32_STATUS_STATE_DISABLED) | |
8676 | break; | 8676 | break; | |
8677 | 8677 | |||
8678 | DELAY(1000); | 8678 | DELAY(1000); | |
8679 | } | 8679 | } | |
8680 | if (i == NRETRY) | 8680 | if (i == NRETRY) | |
8681 | aprint_error_dev(sc->sc_dev, "reset TX ring (%d) timed out\n", | 8681 | aprint_error_dev(sc->sc_dev, "reset TX ring (%d) timed out\n", | |
8682 | ring_idx); | 8682 | ring_idx); | |
8683 | #undef NRETRY | 8683 | #undef NRETRY | |
8684 | 8684 | |||
8685 | DELAY(1000); | 8685 | DELAY(1000); | |
8686 | 8686 | |||
8687 | CSR_WRITE_4(sc, rd->rdata_txrx_ctrl + BWI_TX32_RINGINFO, 0); | 8687 | CSR_WRITE_4(sc, rd->rdata_txrx_ctrl + BWI_TX32_RINGINFO, 0); | |
8688 | 8688 | |||
8689 | for (i = 0; i < BWI_TX_NDESC; ++i) { | 8689 | for (i = 0; i < BWI_TX_NDESC; ++i) { | |
8690 | struct bwi_txbuf *tb = &tbd->tbd_buf[i]; | 8690 | struct bwi_txbuf *tb = &tbd->tbd_buf[i]; | |
8691 | 8691 | |||
8692 | if (tb->tb_mbuf != NULL) { | 8692 | if (tb->tb_mbuf != NULL) { | |
8693 | bus_dmamap_unload(sc->sc_dmat, tb->tb_dmap); | 8693 | bus_dmamap_unload(sc->sc_dmat, tb->tb_dmap); | |
8694 | m_freem(tb->tb_mbuf); | 8694 | m_freem(tb->tb_mbuf); | |
8695 | tb->tb_mbuf = NULL; | 8695 | tb->tb_mbuf = NULL; | |
8696 | } | 8696 | } | |
8697 | if (tb->tb_ni != NULL) { | 8697 | if (tb->tb_ni != NULL) { | |
8698 | ieee80211_free_node(tb->tb_ni); | 8698 | ieee80211_free_node(tb->tb_ni); | |
8699 | tb->tb_ni = NULL; | 8699 | tb->tb_ni = NULL; | |
8700 | } | 8700 | } | |
8701 | } | 8701 | } | |
8702 | } | 8702 | } | |
8703 | 8703 | |||
8704 | static void | 8704 | static void | |
8705 | bwi_free_txstats64(struct bwi_softc *sc) | 8705 | bwi_free_txstats64(struct bwi_softc *sc) | |
8706 | { | 8706 | { | |
8707 | /* TODO: 64 */ | 8707 | /* TODO: 64 */ | |
8708 | } | 8708 | } | |
8709 | 8709 | |||
8710 | static void | 8710 | static void | |
8711 | bwi_free_rx_ring64(struct bwi_softc *sc) | 8711 | bwi_free_rx_ring64(struct bwi_softc *sc) | |
8712 | { | 8712 | { | |
8713 | /* TODO: 64 */ | 8713 | /* TODO: 64 */ | |
8714 | } | 8714 | } | |
8715 | 8715 | |||
8716 | static void | 8716 | static void | |
8717 | bwi_free_tx_ring64(struct bwi_softc *sc, int ring_idx) | 8717 | bwi_free_tx_ring64(struct bwi_softc *sc, int ring_idx) | |
8718 | { | 8718 | { | |
8719 | /* TODO: 64 */ | 8719 | /* TODO: 64 */ | |
8720 | } | 8720 | } | |
8721 | 8721 | |||
8722 | /* XXX does not belong here */ | 8722 | /* XXX does not belong here */ | |
8723 | /* [TRC: Begin pilferage from OpenBSD.] */ | 8723 | /* [TRC: Begin pilferage from OpenBSD.] */ | |
8724 | 8724 | |||
8725 | /* | 8725 | /* | |
8726 | * Convert bit rate (in 0.5Mbps units) to PLCP signal (R4-R1) and vice versa. | 8726 | * Convert bit rate (in 0.5Mbps units) to PLCP signal (R4-R1) and vice versa. | |
8727 | */ | 8727 | */ | |
8728 | uint8_t | 8728 | uint8_t | |
8729 | bwi_ieee80211_rate2plcp(u_int8_t rate, enum ieee80211_phymode mode) | 8729 | bwi_ieee80211_rate2plcp(u_int8_t rate, enum ieee80211_phymode mode) | |
8730 | { | 8730 | { | |
8731 | rate &= IEEE80211_RATE_VAL; | 8731 | rate &= IEEE80211_RATE_VAL; | |
8732 | 8732 | |||
8733 | if (mode == IEEE80211_MODE_11B) { | 8733 | if (mode == IEEE80211_MODE_11B) { | |
8734 | /* IEEE Std 802.11b-1999 page 15, subclause 18.2.3.3 */ | 8734 | /* IEEE Std 802.11b-1999 page 15, subclause 18.2.3.3 */ | |
8735 | switch (rate) { | 8735 | switch (rate) { | |
8736 | case 2: return 10; | 8736 | case 2: return 10; | |
8737 | case 4: return 20; | 8737 | case 4: return 20; | |
8738 | case 11: return 55; | 8738 | case 11: return 55; | |
8739 | case 22: return 110; | 8739 | case 22: return 110; | |
8740 | /* IEEE Std 802.11g-2003 page 19, subclause 19.3.2.1 */ | 8740 | /* IEEE Std 802.11g-2003 page 19, subclause 19.3.2.1 */ | |
8741 | case 44: return 220; | 8741 | case 44: return 220; | |
8742 | } | 8742 | } | |
8743 | } else if (mode == IEEE80211_MODE_11G || mode == IEEE80211_MODE_11A) { | 8743 | } else if (mode == IEEE80211_MODE_11G || mode == IEEE80211_MODE_11A) { | |
8744 | /* IEEE Std 802.11a-1999 page 14, subclause 17.3.4.1 */ | 8744 | /* IEEE Std 802.11a-1999 page 14, subclause 17.3.4.1 */ | |
8745 | switch (rate) { | 8745 | switch (rate) { | |
8746 | case 12: return 0x0b; | 8746 | case 12: return 0x0b; | |
8747 | case 18: return 0x0f; | 8747 | case 18: return 0x0f; | |
8748 | case 24: return 0x0a; | 8748 | case 24: return 0x0a; | |
8749 | case 36: return 0x0e; | 8749 | case 36: return 0x0e; | |
8750 | case 48: return 0x09; | 8750 | case 48: return 0x09; | |
8751 | case 72: return 0x0d; | 8751 | case 72: return 0x0d; | |
8752 | case 96: return 0x08; | 8752 | case 96: return 0x08; | |
8753 | case 108: return 0x0c; | 8753 | case 108: return 0x0c; | |
8754 | } | 8754 | } | |
8755 | } else | 8755 | } else | |
8756 | panic("Unexpected mode %u", mode); | 8756 | panic("Unexpected mode %u", mode); | |
8757 | 8757 | |||
8758 | return 0; | 8758 | return 0; | |
8759 | } | 8759 | } | |
8760 | 8760 | |||
8761 | static uint8_t | 8761 | static uint8_t | |
8762 | bwi_ieee80211_plcp2rate(uint8_t plcp, enum ieee80211_phymode mode) | 8762 | bwi_ieee80211_plcp2rate(uint8_t plcp, enum ieee80211_phymode mode) | |
8763 | { | 8763 | { | |
8764 | if (mode == IEEE80211_MODE_11B) { | 8764 | if (mode == IEEE80211_MODE_11B) { | |
8765 | /* IEEE Std 802.11g-2003 page 19, subclause 19.3.2.1 */ | 8765 | /* IEEE Std 802.11g-2003 page 19, subclause 19.3.2.1 */ | |
8766 | switch (plcp) { | 8766 | switch (plcp) { | |
8767 | case 10: return 2; | 8767 | case 10: return 2; | |
8768 | case 20: return 4; | 8768 | case 20: return 4; | |
8769 | case 55: return 11; | 8769 | case 55: return 11; | |
8770 | case 110: return 22; | 8770 | case 110: return 22; | |
8771 | /* IEEE Std 802.11g-2003 page 19, subclause 19.3.2.1 */ | 8771 | /* IEEE Std 802.11g-2003 page 19, subclause 19.3.2.1 */ | |
8772 | case 220: return 44; | 8772 | case 220: return 44; | |
8773 | } | 8773 | } | |
8774 | } else if (mode == IEEE80211_MODE_11G || mode == IEEE80211_MODE_11A) { | 8774 | } else if (mode == IEEE80211_MODE_11G || mode == IEEE80211_MODE_11A) { | |
8775 | /* IEEE Std 802.11a-1999 page 14, subclause 17.3.4.1 */ | 8775 | /* IEEE Std 802.11a-1999 page 14, subclause 17.3.4.1 */ | |
8776 | switch (plcp) { | 8776 | switch (plcp) { | |
8777 | case 0x0b: return 12; | 8777 | case 0x0b: return 12; | |
8778 | case 0x0f: return 18; | 8778 | case 0x0f: return 18; | |
8779 | case 0x0a: return 24; | 8779 | case 0x0a: return 24; | |
8780 | case 0x0e: return 36; | 8780 | case 0x0e: return 36; | |
8781 | case 0x09: return 48; | 8781 | case 0x09: return 48; | |
8782 | case 0x0d: return 72; | 8782 | case 0x0d: return 72; | |
8783 | case 0x08: return 96; | 8783 | case 0x08: return 96; | |
8784 | case 0x0c: return 108; | 8784 | case 0x0c: return 108; | |
8785 | } | 8785 | } | |
8786 | } else | 8786 | } else | |
8787 | panic("Unexpected mode %u", mode); | 8787 | panic("Unexpected mode %u", mode); | |
8788 | 8788 | |||
8789 | return 0; | 8789 | return 0; | |
8790 | } | 8790 | } | |
8791 | /* [TRC: End pilferage from OpenBSD.] */ | 8791 | /* [TRC: End pilferage from OpenBSD.] */ | |
8792 | 8792 | |||
8793 | static enum bwi_ieee80211_modtype | 8793 | static enum bwi_ieee80211_modtype | |
8794 | bwi_ieee80211_rate2modtype(uint8_t rate) | 8794 | bwi_ieee80211_rate2modtype(uint8_t rate) | |
8795 | { | 8795 | { | |
8796 | rate &= IEEE80211_RATE_VAL; | 8796 | rate &= IEEE80211_RATE_VAL; | |
8797 | 8797 | |||
8798 | if (rate == 44) | 8798 | if (rate == 44) | |
8799 | return (IEEE80211_MODTYPE_PBCC); | 8799 | return (IEEE80211_MODTYPE_PBCC); | |
8800 | else if (rate == 22 || rate < 12) | 8800 | else if (rate == 22 || rate < 12) | |
8801 | return (IEEE80211_MODTYPE_DS); | 8801 | return (IEEE80211_MODTYPE_DS); | |
8802 | else | 8802 | else | |
8803 | return (IEEE80211_MODTYPE_OFDM); | 8803 | return (IEEE80211_MODTYPE_OFDM); | |
8804 | } | 8804 | } | |
8805 | 8805 | |||
8806 | static uint8_t | 8806 | static uint8_t | |
8807 | bwi_ofdm_plcp2rate(const void *plcp0) | 8807 | bwi_ofdm_plcp2rate(const void *plcp0) | |
8808 | { | 8808 | { | |
8809 | uint32_t plcp; | 8809 | uint32_t plcp; | |
8810 | uint8_t plcp_rate; | 8810 | uint8_t plcp_rate; | |
8811 | 8811 | |||
8812 | /* plcp0 may not be 32-bit aligned. */ | 8812 | /* plcp0 may not be 32-bit aligned. */ | |
8813 | plcp = le32dec(plcp0); | 8813 | plcp = le32dec(plcp0); | |
8814 | plcp_rate = __SHIFTOUT(plcp, IEEE80211_OFDM_PLCP_RATE_MASK); | 8814 | plcp_rate = __SHIFTOUT(plcp, IEEE80211_OFDM_PLCP_RATE_MASK); | |
8815 | 8815 | |||
8816 | return (bwi_ieee80211_plcp2rate(plcp_rate, IEEE80211_MODE_11G)); | 8816 | return (bwi_ieee80211_plcp2rate(plcp_rate, IEEE80211_MODE_11G)); | |
8817 | } | 8817 | } | |
8818 | 8818 | |||
8819 | static uint8_t | 8819 | static uint8_t | |
8820 | bwi_ds_plcp2rate(const struct ieee80211_ds_plcp_hdr *hdr) | 8820 | bwi_ds_plcp2rate(const struct ieee80211_ds_plcp_hdr *hdr) | |
8821 | { | 8821 | { | |
8822 | return (bwi_ieee80211_plcp2rate(hdr->i_signal, IEEE80211_MODE_11B)); | 8822 | return (bwi_ieee80211_plcp2rate(hdr->i_signal, IEEE80211_MODE_11B)); | |
8823 | } | 8823 | } | |
8824 | 8824 | |||
8825 | static void | 8825 | static void | |
8826 | bwi_ofdm_plcp_header(uint32_t *plcp0, int pkt_len, uint8_t rate) | 8826 | bwi_ofdm_plcp_header(uint32_t *plcp0, int pkt_len, uint8_t rate) | |
8827 | { | 8827 | { | |
8828 | uint32_t plcp; | 8828 | uint32_t plcp; | |
8829 | 8829 | |||
8830 | plcp = __SHIFTIN(bwi_ieee80211_rate2plcp(rate, IEEE80211_MODE_11G), | 8830 | plcp = __SHIFTIN(bwi_ieee80211_rate2plcp(rate, IEEE80211_MODE_11G), | |
8831 | IEEE80211_OFDM_PLCP_RATE_MASK) | | 8831 | IEEE80211_OFDM_PLCP_RATE_MASK) | | |
8832 | __SHIFTIN(pkt_len, IEEE80211_OFDM_PLCP_LEN_MASK); | 8832 | __SHIFTIN(pkt_len, IEEE80211_OFDM_PLCP_LEN_MASK); | |
8833 | *plcp0 = htole32(plcp); | 8833 | *plcp0 = htole32(plcp); | |
8834 | } | 8834 | } | |
8835 | 8835 | |||
8836 | static void | 8836 | static void | |
8837 | bwi_ds_plcp_header(struct ieee80211_ds_plcp_hdr *plcp, int pkt_len, | 8837 | bwi_ds_plcp_header(struct ieee80211_ds_plcp_hdr *plcp, int pkt_len, | |
8838 | uint8_t rate) | 8838 | uint8_t rate) | |
8839 | { | 8839 | { | |
8840 | int len, service, pkt_bitlen; | 8840 | int len, service, pkt_bitlen; | |
8841 | 8841 | |||
8842 | pkt_bitlen = pkt_len * NBBY; | 8842 | pkt_bitlen = pkt_len * NBBY; | |
8843 | len = howmany(pkt_bitlen * 2, rate); | 8843 | len = howmany(pkt_bitlen * 2, rate); | |
8844 | 8844 | |||
8845 | service = IEEE80211_DS_PLCP_SERVICE_LOCKED; | 8845 | service = IEEE80211_DS_PLCP_SERVICE_LOCKED; | |
8846 | if (rate == (11 * 2)) { | 8846 | if (rate == (11 * 2)) { | |
8847 | int pkt_bitlen1; | 8847 | int pkt_bitlen1; | |
8848 | 8848 | |||
8849 | /* | 8849 | /* | |
8850 | * PLCP service field needs to be adjusted, | 8850 | * PLCP service field needs to be adjusted, | |
8851 | * if TX rate is 11Mbytes/s | 8851 | * if TX rate is 11Mbytes/s | |
8852 | */ | 8852 | */ | |
8853 | pkt_bitlen1 = len * 11; | 8853 | pkt_bitlen1 = len * 11; | |
8854 | if (pkt_bitlen1 - pkt_bitlen >= NBBY) | 8854 | if (pkt_bitlen1 - pkt_bitlen >= NBBY) | |
8855 | service |= IEEE80211_DS_PLCP_SERVICE_LENEXT7; | 8855 | service |= IEEE80211_DS_PLCP_SERVICE_LENEXT7; | |
8856 | } | 8856 | } | |
8857 | 8857 | |||
8858 | plcp->i_signal = bwi_ieee80211_rate2plcp(rate, IEEE80211_MODE_11B); | 8858 | plcp->i_signal = bwi_ieee80211_rate2plcp(rate, IEEE80211_MODE_11B); | |
8859 | plcp->i_service = service; | 8859 | plcp->i_service = service; | |
8860 | plcp->i_length = htole16(len); | 8860 | plcp->i_length = htole16(len); | |
8861 | /* NOTE: do NOT touch i_crc */ | 8861 | /* NOTE: do NOT touch i_crc */ | |
8862 | } | 8862 | } | |
8863 | 8863 | |||
8864 | static void | 8864 | static void | |
8865 | bwi_plcp_header(void *plcp, int pkt_len, uint8_t rate) | 8865 | bwi_plcp_header(void *plcp, int pkt_len, uint8_t rate) | |
8866 | { | 8866 | { | |
8867 | enum bwi_ieee80211_modtype modtype; | 8867 | enum bwi_ieee80211_modtype modtype; | |
8868 | 8868 | |||
8869 | /* | 8869 | /* | |
8870 | * Assume caller has zeroed 'plcp' | 8870 | * Assume caller has zeroed 'plcp' | |
8871 | */ | 8871 | */ | |
8872 | 8872 | |||
8873 | modtype = bwi_ieee80211_rate2modtype(rate); | 8873 | modtype = bwi_ieee80211_rate2modtype(rate); | |
8874 | if (modtype == IEEE80211_MODTYPE_OFDM) | 8874 | if (modtype == IEEE80211_MODTYPE_OFDM) | |
8875 | bwi_ofdm_plcp_header(plcp, pkt_len, rate); | 8875 | bwi_ofdm_plcp_header(plcp, pkt_len, rate); | |
8876 | else if (modtype == IEEE80211_MODTYPE_DS) | 8876 | else if (modtype == IEEE80211_MODTYPE_DS) | |
8877 | bwi_ds_plcp_header(plcp, pkt_len, rate); | 8877 | bwi_ds_plcp_header(plcp, pkt_len, rate); | |
8878 | else | 8878 | else | |
8879 | panic("unsupport modulation type %u\n", modtype); | 8879 | panic("unsupport modulation type %u\n", modtype); | |
8880 | } | 8880 | } | |
8881 | 8881 | |||
8882 | static uint8_t | 8882 | static uint8_t | |
8883 | bwi_ieee80211_ack_rate(struct ieee80211_node *ni, uint8_t rate) | 8883 | bwi_ieee80211_ack_rate(struct ieee80211_node *ni, uint8_t rate) | |
8884 | { | 8884 | { | |
8885 | const struct ieee80211_rateset *rs = &ni->ni_rates; | 8885 | const struct ieee80211_rateset *rs = &ni->ni_rates; | |
8886 | uint8_t ack_rate = 0; | 8886 | uint8_t ack_rate = 0; | |
8887 | enum bwi_ieee80211_modtype modtype; | 8887 | enum bwi_ieee80211_modtype modtype; | |
8888 | int i; | 8888 | int i; | |
8889 | 8889 | |||
8890 | rate &= IEEE80211_RATE_VAL; | 8890 | rate &= IEEE80211_RATE_VAL; | |
8891 | 8891 | |||
8892 | modtype = bwi_ieee80211_rate2modtype(rate); | 8892 | modtype = bwi_ieee80211_rate2modtype(rate); | |
8893 | 8893 | |||
8894 | for (i = 0; i < rs->rs_nrates; ++i) { | 8894 | for (i = 0; i < rs->rs_nrates; ++i) { | |
8895 | uint8_t rate1 = rs->rs_rates[i] & IEEE80211_RATE_VAL; | 8895 | uint8_t rate1 = rs->rs_rates[i] & IEEE80211_RATE_VAL; | |
8896 | 8896 | |||
8897 | if (rate1 > rate) { | 8897 | if (rate1 > rate) { | |
8898 | if (ack_rate != 0) | 8898 | if (ack_rate != 0) | |
8899 | return (ack_rate); | 8899 | return (ack_rate); | |
8900 | else | 8900 | else | |
8901 | break; | 8901 | break; | |
8902 | } | 8902 | } | |
8903 | 8903 | |||
8904 | if ((rs->rs_rates[i] & IEEE80211_RATE_BASIC) && | 8904 | if ((rs->rs_rates[i] & IEEE80211_RATE_BASIC) && | |
8905 | bwi_ieee80211_rate2modtype(rate1) == modtype) | 8905 | bwi_ieee80211_rate2modtype(rate1) == modtype) | |
8906 | ack_rate = rate1; | 8906 | ack_rate = rate1; | |
8907 | } | 8907 | } | |
8908 | 8908 | |||
8909 | switch (rate) { | 8909 | switch (rate) { | |
8910 | /* CCK */ | 8910 | /* CCK */ | |
8911 | case 2: | 8911 | case 2: | |
8912 | case 4: | 8912 | case 4: | |
8913 | case 11: | 8913 | case 11: | |
8914 | case 22: | 8914 | case 22: | |
8915 | ack_rate = rate; | 8915 | ack_rate = rate; | |
8916 | break; | 8916 | break; | |
8917 | /* PBCC */ | 8917 | /* PBCC */ | |
8918 | case 44: | 8918 | case 44: | |
8919 | ack_rate = 22; | 8919 | ack_rate = 22; | |
8920 | break; | 8920 | break; | |
8921 | 8921 | |||
8922 | /* OFDM */ | 8922 | /* OFDM */ | |
8923 | case 12: | 8923 | case 12: | |
8924 | case 18: | 8924 | case 18: | |
8925 | ack_rate = 12; | 8925 | ack_rate = 12; | |
8926 | break; | 8926 | break; | |
8927 | case 24: | 8927 | case 24: | |
8928 | case 36: | 8928 | case 36: | |
8929 | ack_rate = 24; | 8929 | ack_rate = 24; | |
8930 | break; | 8930 | break; | |
8931 | case 48: | 8931 | case 48: | |
8932 | case 72: | 8932 | case 72: | |
8933 | case 96: | 8933 | case 96: | |
8934 | case 108: | 8934 | case 108: | |
8935 | ack_rate = 48; | 8935 | ack_rate = 48; | |
8936 | break; | 8936 | break; | |
8937 | default: | 8937 | default: | |
8938 | panic("unsupported rate %d\n", rate); | 8938 | panic("unsupported rate %d\n", rate); | |
8939 | } | 8939 | } | |
8940 | return (ack_rate); | 8940 | return (ack_rate); | |
8941 | } | 8941 | } | |
8942 | 8942 | |||
8943 | /* [TRC: XXX does not belong here] */ | 8943 | /* [TRC: XXX does not belong here] */ | |
8944 | 8944 | |||
8945 | #define IEEE80211_OFDM_TXTIME(kbps, frmlen) \ | 8945 | #define IEEE80211_OFDM_TXTIME(kbps, frmlen) \ | |
8946 | (IEEE80211_OFDM_PREAMBLE_TIME + \ | 8946 | (IEEE80211_OFDM_PREAMBLE_TIME + \ | |
8947 | IEEE80211_OFDM_SIGNAL_TIME + \ | 8947 | IEEE80211_OFDM_SIGNAL_TIME + \ | |
8948 | (IEEE80211_OFDM_NSYMS((kbps), (frmlen)) * IEEE80211_OFDM_SYM_TIME)) | 8948 | (IEEE80211_OFDM_NSYMS((kbps), (frmlen)) * IEEE80211_OFDM_SYM_TIME)) | |
8949 | 8949 | |||
8950 | #define IEEE80211_OFDM_SYM_TIME 4 | 8950 | #define IEEE80211_OFDM_SYM_TIME 4 | |
8951 | #define IEEE80211_OFDM_PREAMBLE_TIME 16 | 8951 | #define IEEE80211_OFDM_PREAMBLE_TIME 16 | |
8952 | #define IEEE80211_OFDM_SIGNAL_EXT_TIME 6 | 8952 | #define IEEE80211_OFDM_SIGNAL_EXT_TIME 6 | |
8953 | #define IEEE80211_OFDM_SIGNAL_TIME 4 | 8953 | #define IEEE80211_OFDM_SIGNAL_TIME 4 | |
8954 | 8954 | |||
8955 | #define IEEE80211_OFDM_PLCP_SERVICE_NBITS 16 | 8955 | #define IEEE80211_OFDM_PLCP_SERVICE_NBITS 16 | |
8956 | #define IEEE80211_OFDM_TAIL_NBITS 6 | 8956 | #define IEEE80211_OFDM_TAIL_NBITS 6 | |
8957 | 8957 | |||
8958 | #define IEEE80211_OFDM_NBITS(frmlen) \ | 8958 | #define IEEE80211_OFDM_NBITS(frmlen) \ | |
8959 | (IEEE80211_OFDM_PLCP_SERVICE_NBITS + \ | 8959 | (IEEE80211_OFDM_PLCP_SERVICE_NBITS + \ | |
8960 | ((frmlen) * NBBY) + \ | 8960 | ((frmlen) * NBBY) + \ | |
8961 | IEEE80211_OFDM_TAIL_NBITS) | 8961 | IEEE80211_OFDM_TAIL_NBITS) | |
8962 | 8962 | |||
8963 | #define IEEE80211_OFDM_NBITS_PER_SYM(kbps) \ | 8963 | #define IEEE80211_OFDM_NBITS_PER_SYM(kbps) \ | |
8964 | (((kbps) * IEEE80211_OFDM_SYM_TIME) / 1000) | 8964 | (((kbps) * IEEE80211_OFDM_SYM_TIME) / 1000) | |
8965 | 8965 | |||
8966 | #define IEEE80211_OFDM_NSYMS(kbps, frmlen) \ | 8966 | #define IEEE80211_OFDM_NSYMS(kbps, frmlen) \ | |
8967 | howmany(IEEE80211_OFDM_NBITS((frmlen)), \ | 8967 | howmany(IEEE80211_OFDM_NBITS((frmlen)), \ | |
8968 | IEEE80211_OFDM_NBITS_PER_SYM((kbps))) | 8968 | IEEE80211_OFDM_NBITS_PER_SYM((kbps))) | |
8969 | 8969 | |||
8970 | #define IEEE80211_CCK_TXTIME(kbps, frmlen) \ | 8970 | #define IEEE80211_CCK_TXTIME(kbps, frmlen) \ | |
8971 | (((IEEE80211_CCK_NBITS((frmlen)) * 1000) + (kbps) - 1) / (kbps)) | 8971 | (((IEEE80211_CCK_NBITS((frmlen)) * 1000) + (kbps) - 1) / (kbps)) | |
8972 | 8972 | |||
8973 | #define IEEE80211_CCK_PREAMBLE_LEN 144 | 8973 | #define IEEE80211_CCK_PREAMBLE_LEN 144 | |
8974 | #define IEEE80211_CCK_PLCP_HDR_TIME 48 | 8974 | #define IEEE80211_CCK_PLCP_HDR_TIME 48 | |
8975 | #define IEEE80211_CCK_SHPREAMBLE_LEN 72 | 8975 | #define IEEE80211_CCK_SHPREAMBLE_LEN 72 | |
8976 | #define IEEE80211_CCK_SHPLCP_HDR_TIME 24 | 8976 | #define IEEE80211_CCK_SHPLCP_HDR_TIME 24 | |
8977 | 8977 | |||
8978 | #define IEEE80211_CCK_NBITS(frmlen) ((frmlen) * NBBY) | 8978 | #define IEEE80211_CCK_NBITS(frmlen) ((frmlen) * NBBY) | |
8979 | 8979 | |||
8980 | static uint16_t | 8980 | static uint16_t | |
8981 | bwi_ieee80211_txtime(struct ieee80211com *ic, struct ieee80211_node *ni, | 8981 | bwi_ieee80211_txtime(struct ieee80211com *ic, struct ieee80211_node *ni, | |
8982 | uint len, uint8_t rs_rate, uint32_t flags) | 8982 | uint len, uint8_t rs_rate, uint32_t flags) | |
8983 | { | 8983 | { | |
8984 | enum bwi_ieee80211_modtype modtype; | 8984 | enum bwi_ieee80211_modtype modtype; | |
8985 | uint16_t txtime; | 8985 | uint16_t txtime; | |
8986 | int rate; | 8986 | int rate; | |
8987 | 8987 | |||
8988 | rs_rate &= IEEE80211_RATE_VAL; | 8988 | rs_rate &= IEEE80211_RATE_VAL; | |
8989 | 8989 | |||
8990 | rate = rs_rate * 500; /* ieee80211 rate -> kbps */ | 8990 | rate = rs_rate * 500; /* ieee80211 rate -> kbps */ | |
8991 | 8991 | |||
8992 | modtype = bwi_ieee80211_rate2modtype(rs_rate); | 8992 | modtype = bwi_ieee80211_rate2modtype(rs_rate); | |
8993 | if (modtype == IEEE80211_MODTYPE_OFDM) { | 8993 | if (modtype == IEEE80211_MODTYPE_OFDM) { | |
8994 | /* | 8994 | /* | |
8995 | * IEEE Std 802.11a-1999, page 37, equation (29) | 8995 | * IEEE Std 802.11a-1999, page 37, equation (29) | |
8996 | * IEEE Std 802.11g-2003, page 44, equation (42) | 8996 | * IEEE Std 802.11g-2003, page 44, equation (42) | |
8997 | */ | 8997 | */ | |
8998 | txtime = IEEE80211_OFDM_TXTIME(rate, len); | 8998 | txtime = IEEE80211_OFDM_TXTIME(rate, len); | |
8999 | if (ic->ic_curmode == IEEE80211_MODE_11G) | 8999 | if (ic->ic_curmode == IEEE80211_MODE_11G) | |
9000 | txtime += IEEE80211_OFDM_SIGNAL_EXT_TIME; | 9000 | txtime += IEEE80211_OFDM_SIGNAL_EXT_TIME; | |
9001 | } else { | 9001 | } else { | |
9002 | /* | 9002 | /* | |
9003 | * IEEE Std 802.11b-1999, page 28, subclause 18.3.4 | 9003 | * IEEE Std 802.11b-1999, page 28, subclause 18.3.4 | |
9004 | * IEEE Std 802.11g-2003, page 45, equation (43) | 9004 | * IEEE Std 802.11g-2003, page 45, equation (43) | |
9005 | */ | 9005 | */ | |
9006 | if (modtype == IEEE80211_MODTYPE_PBCC) | 9006 | if (modtype == IEEE80211_MODTYPE_PBCC) | |
9007 | ++len; | 9007 | ++len; | |
9008 | txtime = IEEE80211_CCK_TXTIME(rate, len); | 9008 | txtime = IEEE80211_CCK_TXTIME(rate, len); | |
9009 | 9009 | |||
9010 | /* | 9010 | /* | |
9011 | * Short preamble is not applicable for DS 1Mbits/s | 9011 | * Short preamble is not applicable for DS 1Mbits/s | |
9012 | */ | 9012 | */ | |
9013 | if (rs_rate != 2 && (flags & IEEE80211_F_SHPREAMBLE)) { | 9013 | if (rs_rate != 2 && (flags & IEEE80211_F_SHPREAMBLE)) { | |
9014 | txtime += IEEE80211_CCK_SHPREAMBLE_LEN + | 9014 | txtime += IEEE80211_CCK_SHPREAMBLE_LEN + | |
9015 | IEEE80211_CCK_SHPLCP_HDR_TIME; | 9015 | IEEE80211_CCK_SHPLCP_HDR_TIME; | |
9016 | } else { | 9016 | } else { | |
9017 | txtime += IEEE80211_CCK_PREAMBLE_LEN + | 9017 | txtime += IEEE80211_CCK_PREAMBLE_LEN + | |
9018 | IEEE80211_CCK_PLCP_HDR_TIME; | 9018 | IEEE80211_CCK_PLCP_HDR_TIME; | |
9019 | } | 9019 | } | |
9020 | } | 9020 | } | |
9021 | return (txtime); | 9021 | return (txtime); | |
9022 | } | 9022 | } | |
9023 | 9023 | |||
9024 | static int | 9024 | static int | |
9025 | bwi_encap(struct bwi_softc *sc, int idx, struct mbuf *m, | 9025 | bwi_encap(struct bwi_softc *sc, int idx, struct mbuf *m, | |
9026 | struct ieee80211_node **nip, int mgt_pkt) | 9026 | struct ieee80211_node **nip, int mgt_pkt) | |
9027 | { | 9027 | { | |
9028 | struct ieee80211com *ic = &sc->sc_ic; | 9028 | struct ieee80211com *ic = &sc->sc_ic; | |
9029 | struct ieee80211_node *ni = *nip; | 9029 | struct ieee80211_node *ni = *nip; | |
9030 | struct bwi_ring_data *rd = &sc->sc_tx_rdata[BWI_TX_DATA_RING]; | 9030 | struct bwi_ring_data *rd = &sc->sc_tx_rdata[BWI_TX_DATA_RING]; | |
9031 | struct bwi_txbuf_data *tbd = &sc->sc_tx_bdata[BWI_TX_DATA_RING]; | 9031 | struct bwi_txbuf_data *tbd = &sc->sc_tx_bdata[BWI_TX_DATA_RING]; | |
9032 | struct bwi_txbuf *tb = &tbd->tbd_buf[idx]; | 9032 | struct bwi_txbuf *tb = &tbd->tbd_buf[idx]; | |
9033 | struct bwi_mac *mac; | 9033 | struct bwi_mac *mac; | |
9034 | struct bwi_txbuf_hdr *hdr; | 9034 | struct bwi_txbuf_hdr *hdr; | |
9035 | struct ieee80211_frame *wh; | 9035 | struct ieee80211_frame *wh; | |
9036 | uint8_t rate; /* [TRC: XXX Use a fallback rate?] */ | 9036 | uint8_t rate; /* [TRC: XXX Use a fallback rate?] */ | |
9037 | uint32_t mac_ctrl; | 9037 | uint32_t mac_ctrl; | |
9038 | uint16_t phy_ctrl; | 9038 | uint16_t phy_ctrl; | |
9039 | bus_addr_t paddr; | 9039 | bus_addr_t paddr; | |
9040 | int pkt_len, error, mcast_pkt = 0; | 9040 | int pkt_len, error, mcast_pkt = 0; | |
9041 | #if 0 | 9041 | #if 0 | |
9042 | const uint8_t *p; | 9042 | const uint8_t *p; | |
9043 | int i; | 9043 | int i; | |
9044 | #endif | 9044 | #endif | |
9045 | 9045 | |||
9046 | KASSERT(ni != NULL); | 9046 | KASSERT(ni != NULL); | |
9047 | KASSERT(sc->sc_cur_regwin->rw_type == BWI_REGWIN_T_MAC); | 9047 | KASSERT(sc->sc_cur_regwin->rw_type == BWI_REGWIN_T_MAC); | |
9048 | mac = (struct bwi_mac *)sc->sc_cur_regwin; | 9048 | mac = (struct bwi_mac *)sc->sc_cur_regwin; | |
9049 | 9049 | |||
9050 | wh = mtod(m, struct ieee80211_frame *); | 9050 | wh = mtod(m, struct ieee80211_frame *); | |
9051 | 9051 | |||
9052 | /* Get 802.11 frame len before prepending TX header */ | 9052 | /* Get 802.11 frame len before prepending TX header */ | |
9053 | pkt_len = m->m_pkthdr.len + IEEE80211_CRC_LEN; | 9053 | pkt_len = m->m_pkthdr.len + IEEE80211_CRC_LEN; | |
9054 | 9054 | |||
9055 | /* | 9055 | /* | |
9056 | * Find TX rate | 9056 | * Find TX rate | |
9057 | */ | 9057 | */ | |
9058 | memset(tb->tb_rate_idx, 0, sizeof(tb->tb_rate_idx)); | 9058 | memset(tb->tb_rate_idx, 0, sizeof(tb->tb_rate_idx)); | |
9059 | if (!mgt_pkt) { | 9059 | if (!mgt_pkt) { | |
9060 | if (ic->ic_fixed_rate != -1) { | 9060 | if (ic->ic_fixed_rate != -1) { | |
9061 | rate = ic->ic_sup_rates[ic->ic_curmode]. | 9061 | rate = ic->ic_sup_rates[ic->ic_curmode]. | |
9062 | rs_rates[ic->ic_fixed_rate]; | 9062 | rs_rates[ic->ic_fixed_rate]; | |
9063 | /* [TRC: XXX Set fallback rate.] */ | 9063 | /* [TRC: XXX Set fallback rate.] */ | |
9064 | } else { | 9064 | } else { | |
9065 | /* AMRR rate control */ | 9065 | /* AMRR rate control */ | |
9066 | /* [TRC: XXX amrr] */ | 9066 | /* [TRC: XXX amrr] */ | |
9067 | /* rate = ni->ni_rates.rs_rates[ni->ni_txrate]; */ | 9067 | /* rate = ni->ni_rates.rs_rates[ni->ni_txrate]; */ | |
9068 | rate = (1 * 2); | 9068 | rate = (1 * 2); | |
9069 | /* [TRC: XXX Set fallback rate.] */ | 9069 | /* [TRC: XXX Set fallback rate.] */ | |
9070 | } | 9070 | } | |
9071 | } else { | 9071 | } else { | |
9072 | /* Fixed at 1Mbits/s for mgt frames */ | 9072 | /* Fixed at 1Mbits/s for mgt frames */ | |
9073 | /* [TRC: XXX Set fallback rate.] */ | 9073 | /* [TRC: XXX Set fallback rate.] */ | |
9074 | rate = (1 * 2); | 9074 | rate = (1 * 2); | |
9075 | } | 9075 | } | |
9076 | 9076 | |||
9077 | rate &= IEEE80211_RATE_VAL; | 9077 | rate &= IEEE80211_RATE_VAL; | |
9078 | 9078 | |||
9079 | if (IEEE80211_IS_MULTICAST(wh->i_addr1)) { | 9079 | if (IEEE80211_IS_MULTICAST(wh->i_addr1)) { | |
9080 | /* [TRC: XXX Set fallback rate.] */ | 9080 | /* [TRC: XXX Set fallback rate.] */ | |
9081 | rate = ic->ic_mcast_rate; | 9081 | rate = ic->ic_mcast_rate; | |
9082 | mcast_pkt = 1; | 9082 | mcast_pkt = 1; | |
9083 | } | 9083 | } | |
9084 | 9084 | |||
9085 | /* [TRC: XXX Check fallback rate.] */ | 9085 | /* [TRC: XXX Check fallback rate.] */ | |
9086 | if (rate == 0) { | 9086 | if (rate == 0) { | |
9087 | aprint_error_dev(sc->sc_dev, "invalid rate %u", rate); | 9087 | aprint_error_dev(sc->sc_dev, "invalid rate %u", rate); | |
9088 | /* [TRC: In the margin of the following line, | 9088 | /* [TRC: In the margin of the following line, | |
9089 | DragonFlyBSD writes `Force 1Mbits/s', whereas | 9089 | DragonFlyBSD writes `Force 1Mbits/s', whereas | |
9090 | OpenBSD writes `Force 1Mbytes/s'.] */ | 9090 | OpenBSD writes `Force 1Mbytes/s'.] */ | |
9091 | rate = (1 * 2); | 9091 | rate = (1 * 2); | |
9092 | /* [TRC: XXX Set fallback rate.] */ | 9092 | /* [TRC: XXX Set fallback rate.] */ | |
9093 | } | 9093 | } | |
9094 | sc->sc_tx_rate = rate; | 9094 | sc->sc_tx_rate = rate; | |
9095 | 9095 | |||
9096 | /* TX radio tap */ | 9096 | /* TX radio tap */ | |
9097 | if (sc->sc_drvbpf != NULL) { | 9097 | if (sc->sc_drvbpf != NULL) { | |
9098 | struct mbuf mb; | 9098 | struct mbuf mb; | |
9099 | struct bwi_tx_radiotap_hdr *tap = &sc->sc_txtap; | 9099 | struct bwi_tx_radiotap_hdr *tap = &sc->sc_txtap; | |
9100 | 9100 | |||
9101 | tap->wt_flags = 0; | 9101 | tap->wt_flags = 0; | |
9102 | tap->wt_rate = rate; | 9102 | tap->wt_rate = rate; | |
9103 | tap->wt_chan_freq = | 9103 | tap->wt_chan_freq = | |
9104 | htole16(ic->ic_bss->ni_chan->ic_freq); | 9104 | htole16(ic->ic_bss->ni_chan->ic_freq); | |
9105 | tap->wt_chan_flags = | 9105 | tap->wt_chan_flags = | |
9106 | htole16(ic->ic_bss->ni_chan->ic_flags); | 9106 | htole16(ic->ic_bss->ni_chan->ic_flags); | |
9107 | 9107 | |||
9108 | mb.m_data = (void *)tap; | 9108 | mb.m_data = (void *)tap; | |
9109 | mb.m_len = sc->sc_txtap_len; | 9109 | mb.m_len = sc->sc_txtap_len; | |
9110 | mb.m_next = m; | 9110 | mb.m_next = m; | |
9111 | mb.m_nextpkt = NULL; | 9111 | mb.m_nextpkt = NULL; | |
9112 | mb.m_type = 0; | 9112 | mb.m_type = 0; | |
9113 | mb.m_flags = 0; | 9113 | mb.m_flags = 0; | |
9114 | bpf_mtap3(sc->sc_drvbpf, &mb, BPF_D_OUT); | 9114 | bpf_mtap3(sc->sc_drvbpf, &mb, BPF_D_OUT); | |
9115 | } | 9115 | } | |
9116 | 9116 | |||
9117 | /* | 9117 | /* | |
9118 | * Setup the embedded TX header | 9118 | * Setup the embedded TX header | |
9119 | */ | 9119 | */ | |
9120 | M_PREPEND(m, sizeof(*hdr), M_DONTWAIT); | 9120 | M_PREPEND(m, sizeof(*hdr), M_DONTWAIT); | |
9121 | if (m == NULL) { | 9121 | if (m == NULL) { | |
9122 | aprint_error_dev(sc->sc_dev, "prepend TX header failed\n"); | 9122 | aprint_error_dev(sc->sc_dev, "prepend TX header failed\n"); | |
9123 | return (ENOBUFS); | 9123 | return (ENOBUFS); | |
9124 | } | 9124 | } | |
9125 | hdr = mtod(m, struct bwi_txbuf_hdr *); | 9125 | hdr = mtod(m, struct bwi_txbuf_hdr *); | |
9126 | 9126 | |||
9127 | memset(hdr, 0, sizeof(*hdr)); | 9127 | memset(hdr, 0, sizeof(*hdr)); | |
9128 | 9128 | |||
9129 | memcpy(hdr->txh_fc, wh->i_fc, sizeof(hdr->txh_fc)); | 9129 | memcpy(hdr->txh_fc, wh->i_fc, sizeof(hdr->txh_fc)); | |
9130 | memcpy(hdr->txh_addr1, wh->i_addr1, sizeof(hdr->txh_addr1)); | 9130 | memcpy(hdr->txh_addr1, wh->i_addr1, sizeof(hdr->txh_addr1)); | |
9131 | 9131 | |||
9132 | if (!mcast_pkt) { | 9132 | if (!mcast_pkt) { | |
9133 | uint16_t dur; | 9133 | uint16_t dur; | |
9134 | uint8_t ack_rate; | 9134 | uint8_t ack_rate; | |
9135 | 9135 | |||
9136 | /* [TRC: XXX Set fallback rate.] */ | 9136 | /* [TRC: XXX Set fallback rate.] */ | |
9137 | ack_rate = bwi_ieee80211_ack_rate(ni, rate); | 9137 | ack_rate = bwi_ieee80211_ack_rate(ni, rate); | |
9138 | dur = bwi_ieee80211_txtime(ic, ni, | 9138 | dur = bwi_ieee80211_txtime(ic, ni, | |
9139 | sizeof(struct ieee80211_frame_ack) + IEEE80211_CRC_LEN, | 9139 | sizeof(struct ieee80211_frame_ack) + IEEE80211_CRC_LEN, | |
9140 | ack_rate, ic->ic_flags & IEEE80211_F_SHPREAMBLE); | 9140 | ack_rate, ic->ic_flags & IEEE80211_F_SHPREAMBLE); | |
9141 | 9141 | |||
9142 | hdr->txh_fb_duration = htole16(dur); | 9142 | hdr->txh_fb_duration = htole16(dur); | |
9143 | } | 9143 | } | |
9144 | 9144 | |||
9145 | hdr->txh_id = htole16( | 9145 | hdr->txh_id = htole16( | |
9146 | __SHIFTIN(BWI_TX_DATA_RING, BWI_TXH_ID_RING_MASK) | | 9146 | __SHIFTIN(BWI_TX_DATA_RING, BWI_TXH_ID_RING_MASK) | | |
9147 | __SHIFTIN(idx, BWI_TXH_ID_IDX_MASK)); | 9147 | __SHIFTIN(idx, BWI_TXH_ID_IDX_MASK)); | |
9148 | 9148 | |||
9149 | bwi_plcp_header(hdr->txh_plcp, pkt_len, rate); | 9149 | bwi_plcp_header(hdr->txh_plcp, pkt_len, rate); | |
9150 | /* [TRC: XXX Use fallback rate.] */ | 9150 | /* [TRC: XXX Use fallback rate.] */ | |
9151 | bwi_plcp_header(hdr->txh_fb_plcp, pkt_len, rate); | 9151 | bwi_plcp_header(hdr->txh_fb_plcp, pkt_len, rate); | |
9152 | 9152 | |||
9153 | phy_ctrl = __SHIFTIN(mac->mac_rf.rf_ant_mode, | 9153 | phy_ctrl = __SHIFTIN(mac->mac_rf.rf_ant_mode, | |
9154 | BWI_TXH_PHY_C_ANTMODE_MASK); | 9154 | BWI_TXH_PHY_C_ANTMODE_MASK); | |
9155 | if (bwi_ieee80211_rate2modtype(rate) == IEEE80211_MODTYPE_OFDM) | 9155 | if (bwi_ieee80211_rate2modtype(rate) == IEEE80211_MODTYPE_OFDM) | |
9156 | phy_ctrl |= BWI_TXH_PHY_C_OFDM; | 9156 | phy_ctrl |= BWI_TXH_PHY_C_OFDM; | |
9157 | else if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) && rate != (2 * 1)) | 9157 | else if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) && rate != (2 * 1)) | |
9158 | phy_ctrl |= BWI_TXH_PHY_C_SHPREAMBLE; | 9158 | phy_ctrl |= BWI_TXH_PHY_C_SHPREAMBLE; | |
9159 | 9159 | |||
9160 | mac_ctrl = BWI_TXH_MAC_C_HWSEQ | BWI_TXH_MAC_C_FIRST_FRAG; | 9160 | mac_ctrl = BWI_TXH_MAC_C_HWSEQ | BWI_TXH_MAC_C_FIRST_FRAG; | |
9161 | if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) | 9161 | if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) | |
9162 | mac_ctrl |= BWI_TXH_MAC_C_ACK; | 9162 | mac_ctrl |= BWI_TXH_MAC_C_ACK; | |
9163 | if (bwi_ieee80211_rate2modtype(rate) == IEEE80211_MODTYPE_OFDM) | 9163 | if (bwi_ieee80211_rate2modtype(rate) == IEEE80211_MODTYPE_OFDM) | |
9164 | mac_ctrl |= BWI_TXH_MAC_C_FB_OFDM; | 9164 | mac_ctrl |= BWI_TXH_MAC_C_FB_OFDM; | |
9165 | 9165 | |||
9166 | hdr->txh_mac_ctrl = htole32(mac_ctrl); | 9166 | hdr->txh_mac_ctrl = htole32(mac_ctrl); | |
9167 | hdr->txh_phy_ctrl = htole16(phy_ctrl); | 9167 | hdr->txh_phy_ctrl = htole16(phy_ctrl); | |
9168 | 9168 | |||
9169 | /* Catch any further usage */ | 9169 | /* Catch any further usage */ | |
9170 | hdr = NULL; | 9170 | hdr = NULL; | |
9171 | wh = NULL; | 9171 | wh = NULL; | |
9172 | 9172 | |||
9173 | /* DMA load */ | 9173 | /* DMA load */ | |
9174 | error = bus_dmamap_load_mbuf(sc->sc_dmat, tb->tb_dmap, m, | 9174 | error = bus_dmamap_load_mbuf(sc->sc_dmat, tb->tb_dmap, m, | |
9175 | BUS_DMA_NOWAIT); | 9175 | BUS_DMA_NOWAIT); | |
9176 | if (error && error != EFBIG) { | 9176 | if (error && error != EFBIG) { | |
9177 | aprint_error_dev(sc->sc_dev, "can't load TX buffer (1) %d\n", | 9177 | aprint_error_dev(sc->sc_dev, "can't load TX buffer (1) %d\n", | |
9178 | error); | 9178 | error); | |
9179 | goto back; | 9179 | goto back; | |
9180 | } | 9180 | } | |
9181 | 9181 | |||
9182 | if (error) { /* error == EFBIG */ | 9182 | if (error) { /* error == EFBIG */ | |
9183 | struct mbuf *m_new; | 9183 | struct mbuf *m_new; | |
9184 | 9184 | |||
9185 | error = 0; | 9185 | error = 0; | |
9186 | 9186 | |||
9187 | MGETHDR(m_new, M_DONTWAIT, MT_DATA); | 9187 | MGETHDR(m_new, M_DONTWAIT, MT_DATA); | |
9188 | if (m_new == NULL) { | 9188 | if (m_new == NULL) { | |
9189 | error = ENOBUFS; | 9189 | error = ENOBUFS; | |
9190 | aprint_error_dev(sc->sc_dev, | 9190 | aprint_error_dev(sc->sc_dev, | |
9191 | "can't defrag TX buffer (1)\n"); | 9191 | "can't defrag TX buffer (1)\n"); | |
9192 | goto back; | 9192 | goto back; | |
9193 | } | 9193 | } | |
9194 | 9194 | |||
9195 | m_copy_pkthdr(m_new, m); | 9195 | m_copy_pkthdr(m_new, m); | |
9196 | if (m->m_pkthdr.len > MHLEN) { | 9196 | if (m->m_pkthdr.len > MHLEN) { | |
9197 | MCLGET(m_new, M_DONTWAIT); | 9197 | MCLGET(m_new, M_DONTWAIT); | |
9198 | if (!(m_new->m_flags & M_EXT)) { | 9198 | if (!(m_new->m_flags & M_EXT)) { | |
9199 | m_freem(m_new); | 9199 | m_freem(m_new); | |
9200 | error = ENOBUFS; | 9200 | error = ENOBUFS; | |
9201 | } | 9201 | } | |
9202 | } | 9202 | } | |
9203 | 9203 | |||
9204 | if (error) { | 9204 | if (error) { | |
9205 | aprint_error_dev(sc->sc_dev, | 9205 | aprint_error_dev(sc->sc_dev, | |
9206 | "can't defrag TX buffer (2)\n"); | 9206 | "can't defrag TX buffer (2)\n"); | |
9207 | goto back; | 9207 | goto back; | |
9208 | } | 9208 | } | |
9209 | 9209 | |||
9210 | m_copydata(m, 0, m->m_pkthdr.len, mtod(m_new, void *)); | 9210 | m_copydata(m, 0, m->m_pkthdr.len, mtod(m_new, void *)); | |
9211 | m_freem(m); | 9211 | m_freem(m); | |
9212 | m_new->m_len = m_new->m_pkthdr.len; | 9212 | m_new->m_len = m_new->m_pkthdr.len; | |
9213 | m = m_new; | 9213 | m = m_new; | |
9214 | 9214 | |||
9215 | error = bus_dmamap_load_mbuf(sc->sc_dmat, tb->tb_dmap, m, | 9215 | error = bus_dmamap_load_mbuf(sc->sc_dmat, tb->tb_dmap, m, | |
9216 | BUS_DMA_NOWAIT); | 9216 | BUS_DMA_NOWAIT); | |
9217 | if (error) { | 9217 | if (error) { | |
9218 | aprint_error_dev(sc->sc_dev, | 9218 | aprint_error_dev(sc->sc_dev, | |
9219 | "can't load TX buffer (2) %d\n", error); | 9219 | "can't load TX buffer (2) %d\n", error); | |
9220 | goto back; | 9220 | goto back; | |
9221 | } | 9221 | } | |
9222 | } | 9222 | } | |
9223 | error = 0; | 9223 | error = 0; | |
9224 | 9224 | |||
9225 | bus_dmamap_sync(sc->sc_dmat, tb->tb_dmap, 0, | 9225 | bus_dmamap_sync(sc->sc_dmat, tb->tb_dmap, 0, | |
9226 | tb->tb_dmap->dm_mapsize, BUS_DMASYNC_PREWRITE); | 9226 | tb->tb_dmap->dm_mapsize, BUS_DMASYNC_PREWRITE); | |
9227 | 9227 | |||
9228 | if (mgt_pkt || mcast_pkt) { | 9228 | if (mgt_pkt || mcast_pkt) { | |
9229 | /* Don't involve mcast/mgt packets into TX rate control */ | 9229 | /* Don't involve mcast/mgt packets into TX rate control */ | |
9230 | ieee80211_free_node(ni); | 9230 | ieee80211_free_node(ni); | |
9231 | *nip = ni = NULL; | 9231 | *nip = ni = NULL; | |
9232 | } | 9232 | } | |
9233 | 9233 | |||
9234 | tb->tb_mbuf = m; | 9234 | tb->tb_mbuf = m; | |
9235 | tb->tb_ni = ni; | 9235 | tb->tb_ni = ni; | |
9236 | 9236 | |||
9237 | #if 0 | 9237 | #if 0 | |
9238 | p = mtod(m, const uint8_t *); | 9238 | p = mtod(m, const uint8_t *); | |
9239 | for (i = 0; i < m->m_pkthdr.len; ++i) { | 9239 | for (i = 0; i < m->m_pkthdr.len; ++i) { | |
9240 | if (i % 8 == 0) { | 9240 | if (i % 8 == 0) { | |
9241 | if (i != 0) | 9241 | if (i != 0) | |
9242 | aprint_debug("\n"); | 9242 | aprint_debug("\n"); | |
9243 | aprint_debug_dev(sc->sc_dev, ""); | 9243 | aprint_debug_dev(sc->sc_dev, ""); | |
9244 | } | 9244 | } | |
9245 | aprint_debug(" %02x", p[i]); | 9245 | aprint_debug(" %02x", p[i]); | |
9246 | } | 9246 | } | |
9247 | aprint_debug("\n"); | 9247 | aprint_debug("\n"); | |
9248 | #endif | 9248 | #endif | |
9249 | 9249 | |||
9250 | DPRINTF(sc, BWI_DBG_TX, "idx %d, pkt_len %d, buflen %d\n", | 9250 | DPRINTF(sc, BWI_DBG_TX, "idx %d, pkt_len %d, buflen %d\n", | |
9251 | idx, pkt_len, m->m_pkthdr.len); | 9251 | idx, pkt_len, m->m_pkthdr.len); | |
9252 | 9252 | |||
9253 | /* Setup TX descriptor */ | 9253 | /* Setup TX descriptor */ | |
9254 | paddr = tb->tb_dmap->dm_segs[0].ds_addr; | 9254 | paddr = tb->tb_dmap->dm_segs[0].ds_addr; | |
9255 | (sc->sc_setup_txdesc)(sc, rd, idx, paddr, m->m_pkthdr.len); | 9255 | (sc->sc_setup_txdesc)(sc, rd, idx, paddr, m->m_pkthdr.len); | |
9256 | bus_dmamap_sync(sc->sc_dmat, rd->rdata_dmap, 0, | 9256 | bus_dmamap_sync(sc->sc_dmat, rd->rdata_dmap, 0, | |
9257 | rd->rdata_dmap->dm_mapsize, BUS_DMASYNC_PREWRITE); | 9257 | rd->rdata_dmap->dm_mapsize, BUS_DMASYNC_PREWRITE); | |
9258 | 9258 | |||
9259 | /* Kick start */ | 9259 | /* Kick start */ | |
9260 | (sc->sc_start_tx)(sc, rd->rdata_txrx_ctrl, idx); | 9260 | (sc->sc_start_tx)(sc, rd->rdata_txrx_ctrl, idx); | |
9261 | 9261 | |||
9262 | back: | 9262 | back: | |
9263 | if (error) | 9263 | if (error) | |
9264 | m_freem(m); | 9264 | m_freem(m); | |
9265 | return (error); | 9265 | return (error); | |
9266 | } | 9266 | } | |
9267 | 9267 | |||
9268 | static void | 9268 | static void | |
9269 | bwi_start_tx32(struct bwi_softc *sc, uint32_t tx_ctrl, int idx) | 9269 | bwi_start_tx32(struct bwi_softc *sc, uint32_t tx_ctrl, int idx) | |
9270 | { | 9270 | { | |
9271 | idx = (idx + 1) % BWI_TX_NDESC; | 9271 | idx = (idx + 1) % BWI_TX_NDESC; | |
9272 | CSR_WRITE_4(sc, tx_ctrl + BWI_TX32_INDEX, | 9272 | CSR_WRITE_4(sc, tx_ctrl + BWI_TX32_INDEX, | |
9273 | idx * sizeof(struct bwi_desc32)); | 9273 | idx * sizeof(struct bwi_desc32)); | |
9274 | } | 9274 | } | |
9275 | 9275 | |||
9276 | static void | 9276 | static void | |
9277 | bwi_start_tx64(struct bwi_softc *sc, uint32_t tx_ctrl, int idx) | 9277 | bwi_start_tx64(struct bwi_softc *sc, uint32_t tx_ctrl, int idx) | |
9278 | { | 9278 | { | |
9279 | /* TODO: 64 */ | 9279 | /* TODO: 64 */ | |
9280 | } | 9280 | } | |
9281 | 9281 | |||
9282 | static void | 9282 | static void | |
9283 | bwi_txeof_status32(struct bwi_softc *sc) | 9283 | bwi_txeof_status32(struct bwi_softc *sc) | |
9284 | { | 9284 | { | |
9285 | struct ifnet *ifp = &sc->sc_if; | 9285 | struct ifnet *ifp = &sc->sc_if; | |
9286 | uint32_t val, ctrl_base; | 9286 | uint32_t val, ctrl_base; | |
9287 | int end_idx, s; | 9287 | int end_idx, s; | |
9288 | 9288 | |||
9289 | s = splnet(); | 9289 | s = splnet(); | |
9290 | 9290 | |||
9291 | ctrl_base = sc->sc_txstats->stats_ctrl_base; | 9291 | ctrl_base = sc->sc_txstats->stats_ctrl_base; | |
9292 | 9292 | |||
9293 | val = CSR_READ_4(sc, ctrl_base + BWI_RX32_STATUS); | 9293 | val = CSR_READ_4(sc, ctrl_base + BWI_RX32_STATUS); | |
9294 | end_idx = __SHIFTOUT(val, BWI_RX32_STATUS_INDEX_MASK) / | 9294 | end_idx = __SHIFTOUT(val, BWI_RX32_STATUS_INDEX_MASK) / | |
9295 | sizeof(struct bwi_desc32); | 9295 | sizeof(struct bwi_desc32); | |
9296 | 9296 | |||
9297 | bwi_txeof_status(sc, end_idx); | 9297 | bwi_txeof_status(sc, end_idx); | |
9298 | 9298 | |||
9299 | CSR_WRITE_4(sc, ctrl_base + BWI_RX32_INDEX, | 9299 | CSR_WRITE_4(sc, ctrl_base + BWI_RX32_INDEX, | |
9300 | end_idx * sizeof(struct bwi_desc32)); | 9300 | end_idx * sizeof(struct bwi_desc32)); | |
9301 | 9301 | |||
9302 | if ((ifp->if_flags & IFF_OACTIVE) == 0) | 9302 | if ((ifp->if_flags & IFF_OACTIVE) == 0) | |
9303 | ifp->if_start(ifp); /* [TRC: XXX Why not bwi_start?] */ | 9303 | ifp->if_start(ifp); /* [TRC: XXX Why not bwi_start?] */ | |
9304 | 9304 | |||
9305 | splx(s); | 9305 | splx(s); | |
9306 | } | 9306 | } | |
9307 | 9307 | |||
9308 | static void | 9308 | static void | |
9309 | bwi_txeof_status64(struct bwi_softc *sc) | 9309 | bwi_txeof_status64(struct bwi_softc *sc) | |
9310 | { | 9310 | { | |
9311 | /* TODO: 64 */ | 9311 | /* TODO: 64 */ | |
9312 | } | 9312 | } | |
9313 | 9313 | |||
9314 | static void | 9314 | static void | |
9315 | _bwi_txeof(struct bwi_softc *sc, uint16_t tx_id) | 9315 | _bwi_txeof(struct bwi_softc *sc, uint16_t tx_id) | |
9316 | { | 9316 | { | |
9317 | struct ifnet *ifp = &sc->sc_if; | 9317 | struct ifnet *ifp = &sc->sc_if; | |
9318 | struct bwi_txbuf_data *tbd; | 9318 | struct bwi_txbuf_data *tbd; | |
9319 | struct bwi_txbuf *tb; | 9319 | struct bwi_txbuf *tb; | |
9320 | int ring_idx, buf_idx; | 9320 | int ring_idx, buf_idx; | |
9321 | 9321 | |||
9322 | if (tx_id == 0) { | 9322 | if (tx_id == 0) { | |
9323 | /* [TRC: XXX What is the severity of this message?] */ | 9323 | /* [TRC: XXX What is the severity of this message?] */ | |
9324 | aprint_normal_dev(sc->sc_dev, "zero tx id\n"); | 9324 | aprint_normal_dev(sc->sc_dev, "zero tx id\n"); | |
9325 | return; | 9325 | return; | |
9326 | } | 9326 | } | |
9327 | 9327 | |||
9328 | ring_idx = __SHIFTOUT(tx_id, BWI_TXH_ID_RING_MASK); | 9328 | ring_idx = __SHIFTOUT(tx_id, BWI_TXH_ID_RING_MASK); | |
9329 | buf_idx = __SHIFTOUT(tx_id, BWI_TXH_ID_IDX_MASK); | 9329 | buf_idx = __SHIFTOUT(tx_id, BWI_TXH_ID_IDX_MASK); | |
9330 | 9330 | |||
9331 | KASSERT(ring_idx == BWI_TX_DATA_RING); | 9331 | KASSERT(ring_idx == BWI_TX_DATA_RING); | |
9332 | KASSERT(buf_idx < BWI_TX_NDESC); | 9332 | KASSERT(buf_idx < BWI_TX_NDESC); | |
9333 | tbd = &sc->sc_tx_bdata[ring_idx]; | 9333 | tbd = &sc->sc_tx_bdata[ring_idx]; | |
9334 | KASSERT(tbd->tbd_used > 0); | 9334 | KASSERT(tbd->tbd_used > 0); | |
9335 | tbd->tbd_used--; | 9335 | tbd->tbd_used--; | |
9336 | 9336 | |||
9337 | tb = &tbd->tbd_buf[buf_idx]; | 9337 | tb = &tbd->tbd_buf[buf_idx]; | |
9338 | 9338 | |||
9339 | bus_dmamap_unload(sc->sc_dmat, tb->tb_dmap); | 9339 | bus_dmamap_unload(sc->sc_dmat, tb->tb_dmap); | |
9340 | m_freem(tb->tb_mbuf); | 9340 | m_freem(tb->tb_mbuf); | |
9341 | tb->tb_mbuf = NULL; | 9341 | tb->tb_mbuf = NULL; | |
9342 | 9342 | |||
9343 | if (tb->tb_ni != NULL) { | 9343 | if (tb->tb_ni != NULL) { | |
9344 | ieee80211_free_node(tb->tb_ni); | 9344 | ieee80211_free_node(tb->tb_ni); | |
9345 | tb->tb_ni = NULL; | 9345 | tb->tb_ni = NULL; | |
9346 | } | 9346 | } | |
9347 | 9347 | |||
9348 | if (tbd->tbd_used == 0) | 9348 | if (tbd->tbd_used == 0) | |
9349 | sc->sc_tx_timer = 0; | 9349 | sc->sc_tx_timer = 0; | |
9350 | 9350 | |||
9351 | ifp->if_flags &= ~IFF_OACTIVE; | 9351 | ifp->if_flags &= ~IFF_OACTIVE; | |
9352 | } | 9352 | } | |
9353 | 9353 | |||
9354 | static void | 9354 | static void | |
9355 | bwi_txeof_status(struct bwi_softc *sc, int end_idx) | 9355 | bwi_txeof_status(struct bwi_softc *sc, int end_idx) | |
9356 | { | 9356 | { | |
9357 | struct bwi_txstats_data *st = sc->sc_txstats; | 9357 | struct bwi_txstats_data *st = sc->sc_txstats; | |
9358 | int idx; | 9358 | int idx; | |
9359 | 9359 | |||
9360 | bus_dmamap_sync(sc->sc_dmat, st->stats_dmap, 0, | 9360 | bus_dmamap_sync(sc->sc_dmat, st->stats_dmap, 0, | |
9361 | st->stats_dmap->dm_mapsize, BUS_DMASYNC_POSTREAD); | 9361 | st->stats_dmap->dm_mapsize, BUS_DMASYNC_POSTREAD); | |
9362 | 9362 | |||
9363 | idx = st->stats_idx; | 9363 | idx = st->stats_idx; | |
9364 | while (idx != end_idx) { | 9364 | while (idx != end_idx) { | |
9365 | /* [TRC: XXX Filter this out if it is not pending; see | 9365 | /* [TRC: XXX Filter this out if it is not pending; see | |
9366 | DragonFlyBSD's revision 1.5. */ | 9366 | DragonFlyBSD's revision 1.5. */ | |
9367 | _bwi_txeof(sc, le16toh(st->stats[idx].txs_id)); | 9367 | _bwi_txeof(sc, le16toh(st->stats[idx].txs_id)); | |
9368 | idx = (idx + 1) % BWI_TXSTATS_NDESC; | 9368 | idx = (idx + 1) % BWI_TXSTATS_NDESC; | |
9369 | } | 9369 | } | |
9370 | st->stats_idx = idx; | 9370 | st->stats_idx = idx; | |
9371 | } | 9371 | } | |
9372 | 9372 | |||
9373 | static void | 9373 | static void | |
9374 | bwi_txeof(struct bwi_softc *sc) | 9374 | bwi_txeof(struct bwi_softc *sc) | |
9375 | { | 9375 | { | |
9376 | struct ifnet *ifp = &sc->sc_if; | 9376 | struct ifnet *ifp = &sc->sc_if; | |
9377 | int s; | 9377 | int s; | |
9378 | 9378 | |||
9379 | s = splnet(); | 9379 | s = splnet(); | |
9380 | 9380 | |||
9381 | for (;;) { | 9381 | for (;;) { | |
9382 | uint32_t tx_status0; | 9382 | uint32_t tx_status0; | |
9383 | uint16_t tx_id, tx_info; | 9383 | uint16_t tx_id, tx_info; | |
9384 | 9384 | |||
9385 | tx_status0 = CSR_READ_4(sc, BWI_TXSTATUS_0); | 9385 | tx_status0 = CSR_READ_4(sc, BWI_TXSTATUS_0); | |
9386 | if ((tx_status0 & BWI_TXSTATUS_0_MORE) == 0) | 9386 | if ((tx_status0 & BWI_TXSTATUS_0_MORE) == 0) | |
9387 | break; | 9387 | break; | |
9388 | (void)CSR_READ_4(sc, BWI_TXSTATUS_1); | 9388 | (void)CSR_READ_4(sc, BWI_TXSTATUS_1); | |
9389 | 9389 | |||
9390 | tx_id = __SHIFTOUT(tx_status0, BWI_TXSTATUS_0_TXID_MASK); | 9390 | tx_id = __SHIFTOUT(tx_status0, BWI_TXSTATUS_0_TXID_MASK); | |
9391 | tx_info = BWI_TXSTATUS_0_INFO(tx_status0); | 9391 | tx_info = BWI_TXSTATUS_0_INFO(tx_status0); | |
9392 | 9392 | |||
9393 | if (tx_info & 0x30) /* XXX */ | 9393 | if (tx_info & 0x30) /* XXX */ | |
9394 | continue; | 9394 | continue; | |
9395 | 9395 | |||
9396 | _bwi_txeof(sc, tx_id); | 9396 | _bwi_txeof(sc, tx_id); | |
9397 | 9397 | |||
9398 | ifp->if_opackets++; | 9398 | if_statinc(ifp, if_opackets); | |
9399 | } | 9399 | } | |
9400 | 9400 | |||
9401 | if ((ifp->if_flags & IFF_OACTIVE) == 0) | 9401 | if ((ifp->if_flags & IFF_OACTIVE) == 0) | |
9402 | ifp->if_start(ifp); | 9402 | ifp->if_start(ifp); | |
9403 | 9403 | |||
9404 | splx(s); | 9404 | splx(s); | |
9405 | } | 9405 | } | |
9406 | 9406 | |||
9407 | static int | 9407 | static int | |
9408 | bwi_bbp_power_on(struct bwi_softc *sc, enum bwi_clock_mode clk_mode) | 9408 | bwi_bbp_power_on(struct bwi_softc *sc, enum bwi_clock_mode clk_mode) | |
9409 | { | 9409 | { | |
9410 | bwi_power_on(sc, 1); | 9410 | bwi_power_on(sc, 1); | |
9411 | 9411 | |||
9412 | return (bwi_set_clock_mode(sc, clk_mode)); | 9412 | return (bwi_set_clock_mode(sc, clk_mode)); | |
9413 | } | 9413 | } | |
9414 | 9414 | |||
9415 | static void | 9415 | static void | |
9416 | bwi_bbp_power_off(struct bwi_softc *sc) | 9416 | bwi_bbp_power_off(struct bwi_softc *sc) | |
9417 | { | 9417 | { | |
9418 | bwi_set_clock_mode(sc, BWI_CLOCK_MODE_SLOW); | 9418 | bwi_set_clock_mode(sc, BWI_CLOCK_MODE_SLOW); | |
9419 | bwi_power_off(sc, 1); | 9419 | bwi_power_off(sc, 1); | |
9420 | } | 9420 | } | |
9421 | 9421 | |||
9422 | static int | 9422 | static int | |
9423 | bwi_get_pwron_delay(struct bwi_softc *sc) | 9423 | bwi_get_pwron_delay(struct bwi_softc *sc) | |
9424 | { | 9424 | { | |
9425 | struct bwi_regwin *com, *old; | 9425 | struct bwi_regwin *com, *old; | |
9426 | struct bwi_clock_freq freq; | 9426 | struct bwi_clock_freq freq; | |
9427 | uint32_t val; | 9427 | uint32_t val; | |
9428 | int error; | 9428 | int error; | |
9429 | 9429 | |||
9430 | com = &sc->sc_com_regwin; | 9430 | com = &sc->sc_com_regwin; | |
9431 | KASSERT(BWI_REGWIN_EXIST(com)); | 9431 | KASSERT(BWI_REGWIN_EXIST(com)); | |
9432 | 9432 | |||
9433 | if ((sc->sc_cap & BWI_CAP_CLKMODE) == 0) | 9433 | if ((sc->sc_cap & BWI_CAP_CLKMODE) == 0) | |
9434 | return (0); | 9434 | return (0); | |
9435 | 9435 | |||
9436 | error = bwi_regwin_switch(sc, com, &old); | 9436 | error = bwi_regwin_switch(sc, com, &old); | |
9437 | if (error) | 9437 | if (error) | |
9438 | return (error); | 9438 | return (error); | |
9439 | 9439 | |||
9440 | bwi_get_clock_freq(sc, &freq); | 9440 | bwi_get_clock_freq(sc, &freq); | |
9441 | 9441 | |||
9442 | val = CSR_READ_4(sc, BWI_PLL_ON_DELAY); | 9442 | val = CSR_READ_4(sc, BWI_PLL_ON_DELAY); | |
9443 | sc->sc_pwron_delay = howmany((val + 2) * 1000000, freq.clkfreq_min); | 9443 | sc->sc_pwron_delay = howmany((val + 2) * 1000000, freq.clkfreq_min); | |
9444 | DPRINTF(sc, BWI_DBG_ATTACH, "power on delay %u\n", sc->sc_pwron_delay); | 9444 | DPRINTF(sc, BWI_DBG_ATTACH, "power on delay %u\n", sc->sc_pwron_delay); | |
9445 | 9445 | |||
9446 | return (bwi_regwin_switch(sc, old, NULL)); | 9446 | return (bwi_regwin_switch(sc, old, NULL)); | |
9447 | } | 9447 | } | |
9448 | 9448 | |||
9449 | static int | 9449 | static int | |
9450 | bwi_bus_attach(struct bwi_softc *sc) | 9450 | bwi_bus_attach(struct bwi_softc *sc) | |
9451 | { | 9451 | { | |
9452 | struct bwi_regwin *bus, *old; | 9452 | struct bwi_regwin *bus, *old; | |
9453 | int error; | 9453 | int error; | |
9454 | 9454 | |||
9455 | bus = &sc->sc_bus_regwin; | 9455 | bus = &sc->sc_bus_regwin; | |
9456 | 9456 | |||
9457 | error = bwi_regwin_switch(sc, bus, &old); | 9457 | error = bwi_regwin_switch(sc, bus, &old); | |
9458 | if (error) | 9458 | if (error) | |
9459 | return (error); | 9459 | return (error); | |
9460 | 9460 | |||
9461 | if (!bwi_regwin_is_enabled(sc, bus)) | 9461 | if (!bwi_regwin_is_enabled(sc, bus)) | |
9462 | bwi_regwin_enable(sc, bus, 0); | 9462 | bwi_regwin_enable(sc, bus, 0); | |
9463 | 9463 | |||
9464 | /* Disable interripts */ | 9464 | /* Disable interripts */ | |
9465 | CSR_WRITE_4(sc, BWI_INTRVEC, 0); | 9465 | CSR_WRITE_4(sc, BWI_INTRVEC, 0); | |
9466 | 9466 | |||
9467 | return (bwi_regwin_switch(sc, old, NULL)); | 9467 | return (bwi_regwin_switch(sc, old, NULL)); | |
9468 | } | 9468 | } | |
9469 | 9469 | |||
9470 | static const char * | 9470 | static const char * | |
9471 | bwi_regwin_name(const struct bwi_regwin *rw) | 9471 | bwi_regwin_name(const struct bwi_regwin *rw) | |
9472 | { | 9472 | { | |
9473 | switch (rw->rw_type) { | 9473 | switch (rw->rw_type) { | |
9474 | case BWI_REGWIN_T_COM: | 9474 | case BWI_REGWIN_T_COM: | |
9475 | return ("COM"); | 9475 | return ("COM"); | |
9476 | case BWI_REGWIN_T_BUSPCI: | 9476 | case BWI_REGWIN_T_BUSPCI: | |
9477 | return ("PCI"); | 9477 | return ("PCI"); | |
9478 | case BWI_REGWIN_T_MAC: | 9478 | case BWI_REGWIN_T_MAC: | |
9479 | return ("MAC"); | 9479 | return ("MAC"); | |
9480 | case BWI_REGWIN_T_BUSPCIE: | 9480 | case BWI_REGWIN_T_BUSPCIE: | |
9481 | return ("PCIE"); | 9481 | return ("PCIE"); | |
9482 | } | 9482 | } | |
9483 | panic("unknown regwin type 0x%04x\n", rw->rw_type); | 9483 | panic("unknown regwin type 0x%04x\n", rw->rw_type); | |
9484 | 9484 | |||
9485 | return (NULL); | 9485 | return (NULL); | |
9486 | } | 9486 | } | |
9487 | 9487 | |||
9488 | static uint32_t | 9488 | static uint32_t | |
9489 | bwi_regwin_disable_bits(struct bwi_softc *sc) | 9489 | bwi_regwin_disable_bits(struct bwi_softc *sc) | |
9490 | { | 9490 | { | |
9491 | uint32_t busrev; | 9491 | uint32_t busrev; | |
9492 | 9492 | |||
9493 | /* XXX cache this */ | 9493 | /* XXX cache this */ | |
9494 | busrev = __SHIFTOUT(CSR_READ_4(sc, BWI_ID_LO), BWI_ID_LO_BUSREV_MASK); | 9494 | busrev = __SHIFTOUT(CSR_READ_4(sc, BWI_ID_LO), BWI_ID_LO_BUSREV_MASK); | |
9495 | DPRINTF(sc, BWI_DBG_ATTACH | BWI_DBG_INIT | BWI_DBG_MISC, | 9495 | DPRINTF(sc, BWI_DBG_ATTACH | BWI_DBG_INIT | BWI_DBG_MISC, | |
9496 | "bus rev %u\n", busrev); | 9496 | "bus rev %u\n", busrev); | |
9497 | 9497 | |||
9498 | if (busrev == BWI_BUSREV_0) | 9498 | if (busrev == BWI_BUSREV_0) | |
9499 | return (BWI_STATE_LO_DISABLE1); | 9499 | return (BWI_STATE_LO_DISABLE1); | |
9500 | else if (busrev == BWI_BUSREV_1) | 9500 | else if (busrev == BWI_BUSREV_1) | |
9501 | return (BWI_STATE_LO_DISABLE2); | 9501 | return (BWI_STATE_LO_DISABLE2); | |
9502 | else | 9502 | else | |
9503 | return (BWI_STATE_LO_DISABLE1 | BWI_STATE_LO_DISABLE2); | 9503 | return (BWI_STATE_LO_DISABLE1 | BWI_STATE_LO_DISABLE2); | |
9504 | } | 9504 | } | |
9505 | 9505 | |||
9506 | static int | 9506 | static int | |
9507 | bwi_regwin_is_enabled(struct bwi_softc *sc, struct bwi_regwin *rw) | 9507 | bwi_regwin_is_enabled(struct bwi_softc *sc, struct bwi_regwin *rw) | |
9508 | { | 9508 | { | |
9509 | uint32_t val, disable_bits; | 9509 | uint32_t val, disable_bits; | |
9510 | 9510 | |||
9511 | disable_bits = bwi_regwin_disable_bits(sc); | 9511 | disable_bits = bwi_regwin_disable_bits(sc); | |
9512 | val = CSR_READ_4(sc, BWI_STATE_LO); | 9512 | val = CSR_READ_4(sc, BWI_STATE_LO); | |
9513 | 9513 | |||
9514 | if ((val & (BWI_STATE_LO_CLOCK | | 9514 | if ((val & (BWI_STATE_LO_CLOCK | | |
9515 | BWI_STATE_LO_RESET | | 9515 | BWI_STATE_LO_RESET | | |
9516 | disable_bits)) == BWI_STATE_LO_CLOCK) { | 9516 | disable_bits)) == BWI_STATE_LO_CLOCK) { | |
9517 | DPRINTF(sc, BWI_DBG_ATTACH | BWI_DBG_INIT, "%s is enabled\n", | 9517 | DPRINTF(sc, BWI_DBG_ATTACH | BWI_DBG_INIT, "%s is enabled\n", | |
9518 | bwi_regwin_name(rw)); | 9518 | bwi_regwin_name(rw)); | |
9519 | return (1); | 9519 | return (1); | |
9520 | } else { | 9520 | } else { | |
9521 | DPRINTF(sc, BWI_DBG_ATTACH | BWI_DBG_INIT, "%s is disabled\n", | 9521 | DPRINTF(sc, BWI_DBG_ATTACH | BWI_DBG_INIT, "%s is disabled\n", | |
9522 | bwi_regwin_name(rw)); | 9522 | bwi_regwin_name(rw)); | |
9523 | return (0); | 9523 | return (0); | |
9524 | } | 9524 | } | |
9525 | } | 9525 | } | |
9526 | 9526 | |||
9527 | static void | 9527 | static void | |
9528 | bwi_regwin_disable(struct bwi_softc *sc, struct bwi_regwin *rw, uint32_t flags) | 9528 | bwi_regwin_disable(struct bwi_softc *sc, struct bwi_regwin *rw, uint32_t flags) | |
9529 | { | 9529 | { | |
9530 | uint32_t state_lo, disable_bits; | 9530 | uint32_t state_lo, disable_bits; | |
9531 | int i; | 9531 | int i; | |
9532 | 9532 | |||
9533 | state_lo = CSR_READ_4(sc, BWI_STATE_LO); | 9533 | state_lo = CSR_READ_4(sc, BWI_STATE_LO); | |
9534 | 9534 | |||
9535 | /* | 9535 | /* | |
9536 | * If current regwin is in 'reset' state, it was already disabled. | 9536 | * If current regwin is in 'reset' state, it was already disabled. | |
9537 | */ | 9537 | */ | |
9538 | if (state_lo & BWI_STATE_LO_RESET) { | 9538 | if (state_lo & BWI_STATE_LO_RESET) { | |
9539 | DPRINTF(sc, BWI_DBG_ATTACH | BWI_DBG_INIT, | 9539 | DPRINTF(sc, BWI_DBG_ATTACH | BWI_DBG_INIT, | |
9540 | "%s was already disabled\n", bwi_regwin_name(rw)); | 9540 | "%s was already disabled\n", bwi_regwin_name(rw)); | |
9541 | return; | 9541 | return; | |
9542 | } | 9542 | } | |
9543 | 9543 | |||
9544 | disable_bits = bwi_regwin_disable_bits(sc); | 9544 | disable_bits = bwi_regwin_disable_bits(sc); | |
9545 | 9545 | |||
9546 | /* | 9546 | /* | |
9547 | * Disable normal clock | 9547 | * Disable normal clock | |
9548 | */ | 9548 | */ | |
9549 | state_lo = BWI_STATE_LO_CLOCK | disable_bits; | 9549 | state_lo = BWI_STATE_LO_CLOCK | disable_bits; | |
9550 | CSR_WRITE_4(sc, BWI_STATE_LO, state_lo); | 9550 | CSR_WRITE_4(sc, BWI_STATE_LO, state_lo); | |
9551 | 9551 | |||
9552 | /* | 9552 | /* | |
9553 | * Wait until normal clock is disabled | 9553 | * Wait until normal clock is disabled | |
9554 | */ | 9554 | */ | |
9555 | #define NRETRY 1000 | 9555 | #define NRETRY 1000 | |
9556 | for (i = 0; i < NRETRY; ++i) { | 9556 | for (i = 0; i < NRETRY; ++i) { | |
9557 | state_lo = CSR_READ_4(sc, BWI_STATE_LO); | 9557 | state_lo = CSR_READ_4(sc, BWI_STATE_LO); | |
9558 | if (state_lo & disable_bits) | 9558 | if (state_lo & disable_bits) | |
9559 | break; | 9559 | break; | |
9560 | DELAY(10); | 9560 | DELAY(10); | |
9561 | } | 9561 | } | |
9562 | if (i == NRETRY) { | 9562 | if (i == NRETRY) { | |
9563 | aprint_error_dev(sc->sc_dev, "%s disable clock timeout\n", | 9563 | aprint_error_dev(sc->sc_dev, "%s disable clock timeout\n", | |
9564 | bwi_regwin_name(rw)); | 9564 | bwi_regwin_name(rw)); | |
9565 | } | 9565 | } | |
9566 | 9566 | |||
9567 | for (i = 0; i < NRETRY; ++i) { | 9567 | for (i = 0; i < NRETRY; ++i) { | |
9568 | uint32_t state_hi; | 9568 | uint32_t state_hi; | |
9569 | 9569 | |||
9570 | state_hi = CSR_READ_4(sc, BWI_STATE_HI); | 9570 | state_hi = CSR_READ_4(sc, BWI_STATE_HI); | |
9571 | if ((state_hi & BWI_STATE_HI_BUSY) == 0) | 9571 | if ((state_hi & BWI_STATE_HI_BUSY) == 0) | |
9572 | break; | 9572 | break; | |
9573 | DELAY(10); | 9573 | DELAY(10); | |
9574 | } | 9574 | } | |
9575 | if (i == NRETRY) { | 9575 | if (i == NRETRY) { | |
9576 | aprint_error_dev(sc->sc_dev, "%s wait BUSY unset timeout\n", | 9576 | aprint_error_dev(sc->sc_dev, "%s wait BUSY unset timeout\n", | |
9577 | bwi_regwin_name(rw)); | 9577 | bwi_regwin_name(rw)); | |
9578 | } | 9578 | } | |
9579 | #undef NRETRY | 9579 | #undef NRETRY | |
9580 | 9580 | |||
9581 | /* | 9581 | /* | |
9582 | * Reset and disable regwin with gated clock | 9582 | * Reset and disable regwin with gated clock | |
9583 | */ | 9583 | */ | |
9584 | state_lo = BWI_STATE_LO_RESET | disable_bits | | 9584 | state_lo = BWI_STATE_LO_RESET | disable_bits | | |
9585 | BWI_STATE_LO_CLOCK | BWI_STATE_LO_GATED_CLOCK | | 9585 | BWI_STATE_LO_CLOCK | BWI_STATE_LO_GATED_CLOCK | | |
9586 | __SHIFTIN(flags, BWI_STATE_LO_FLAGS_MASK); | 9586 | __SHIFTIN(flags, BWI_STATE_LO_FLAGS_MASK); | |
9587 | CSR_WRITE_4(sc, BWI_STATE_LO, state_lo); | 9587 | CSR_WRITE_4(sc, BWI_STATE_LO, state_lo); | |
9588 | 9588 | |||
9589 | /* Flush pending bus write */ | 9589 | /* Flush pending bus write */ | |
9590 | CSR_READ_4(sc, BWI_STATE_LO); | 9590 | CSR_READ_4(sc, BWI_STATE_LO); | |
9591 | DELAY(1); | 9591 | DELAY(1); | |
9592 | 9592 | |||
9593 | /* Reset and disable regwin */ | 9593 | /* Reset and disable regwin */ | |
9594 | state_lo = BWI_STATE_LO_RESET | disable_bits | | 9594 | state_lo = BWI_STATE_LO_RESET | disable_bits | | |
9595 | __SHIFTIN(flags, BWI_STATE_LO_FLAGS_MASK); | 9595 | __SHIFTIN(flags, BWI_STATE_LO_FLAGS_MASK); | |
9596 | CSR_WRITE_4(sc, BWI_STATE_LO, state_lo); | 9596 | CSR_WRITE_4(sc, BWI_STATE_LO, state_lo); | |
9597 | 9597 | |||
9598 | /* Flush pending bus write */ | 9598 | /* Flush pending bus write */ | |
9599 | CSR_READ_4(sc, BWI_STATE_LO); | 9599 | CSR_READ_4(sc, BWI_STATE_LO); | |
9600 | DELAY(1); | 9600 | DELAY(1); | |
9601 | } | 9601 | } | |
9602 | 9602 | |||
9603 | static void | 9603 | static void | |
9604 | bwi_regwin_enable(struct bwi_softc *sc, struct bwi_regwin *rw, uint32_t flags) | 9604 | bwi_regwin_enable(struct bwi_softc *sc, struct bwi_regwin *rw, uint32_t flags) | |
9605 | { | 9605 | { | |
9606 | uint32_t state_lo, state_hi, imstate; | 9606 | uint32_t state_lo, state_hi, imstate; | |
9607 | 9607 | |||
9608 | bwi_regwin_disable(sc, rw, flags); | 9608 | bwi_regwin_disable(sc, rw, flags); | |
9609 | 9609 | |||
9610 | /* Reset regwin with gated clock */ | 9610 | /* Reset regwin with gated clock */ | |
9611 | state_lo = BWI_STATE_LO_RESET | | 9611 | state_lo = BWI_STATE_LO_RESET | | |
9612 | BWI_STATE_LO_CLOCK | | 9612 | BWI_STATE_LO_CLOCK | | |
9613 | BWI_STATE_LO_GATED_CLOCK | | 9613 | BWI_STATE_LO_GATED_CLOCK | | |
9614 | __SHIFTIN(flags, BWI_STATE_LO_FLAGS_MASK); | 9614 | __SHIFTIN(flags, BWI_STATE_LO_FLAGS_MASK); | |
9615 | CSR_WRITE_4(sc, BWI_STATE_LO, state_lo); | 9615 | CSR_WRITE_4(sc, BWI_STATE_LO, state_lo); | |
9616 | 9616 | |||
9617 | /* Flush pending bus write */ | 9617 | /* Flush pending bus write */ | |
9618 | CSR_READ_4(sc, BWI_STATE_LO); | 9618 | CSR_READ_4(sc, BWI_STATE_LO); | |
9619 | DELAY(1); | 9619 | DELAY(1); | |
9620 | 9620 | |||
9621 | state_hi = CSR_READ_4(sc, BWI_STATE_HI); | 9621 | state_hi = CSR_READ_4(sc, BWI_STATE_HI); | |
9622 | if (state_hi & BWI_STATE_HI_SERROR) | 9622 | if (state_hi & BWI_STATE_HI_SERROR) | |
9623 | CSR_WRITE_4(sc, BWI_STATE_HI, 0); | 9623 | CSR_WRITE_4(sc, BWI_STATE_HI, 0); | |
9624 | 9624 | |||
9625 | imstate = CSR_READ_4(sc, BWI_IMSTATE); | 9625 | imstate = CSR_READ_4(sc, BWI_IMSTATE); | |
9626 | if (imstate & (BWI_IMSTATE_INBAND_ERR | BWI_IMSTATE_TIMEOUT)) { | 9626 | if (imstate & (BWI_IMSTATE_INBAND_ERR | BWI_IMSTATE_TIMEOUT)) { | |
9627 | imstate &= ~(BWI_IMSTATE_INBAND_ERR | BWI_IMSTATE_TIMEOUT); | 9627 | imstate &= ~(BWI_IMSTATE_INBAND_ERR | BWI_IMSTATE_TIMEOUT); | |
9628 | CSR_WRITE_4(sc, BWI_IMSTATE, imstate); | 9628 | CSR_WRITE_4(sc, BWI_IMSTATE, imstate); | |
9629 | } | 9629 | } | |
9630 | 9630 | |||
9631 | /* Enable regwin with gated clock */ | 9631 | /* Enable regwin with gated clock */ | |
9632 | state_lo = BWI_STATE_LO_CLOCK | | 9632 | state_lo = BWI_STATE_LO_CLOCK | | |
9633 | BWI_STATE_LO_GATED_CLOCK | | 9633 | BWI_STATE_LO_GATED_CLOCK | | |
9634 | __SHIFTIN(flags, BWI_STATE_LO_FLAGS_MASK); | 9634 | __SHIFTIN(flags, BWI_STATE_LO_FLAGS_MASK); | |
9635 | CSR_WRITE_4(sc, BWI_STATE_LO, state_lo); | 9635 | CSR_WRITE_4(sc, BWI_STATE_LO, state_lo); | |
9636 | 9636 | |||
9637 | /* Flush pending bus write */ | 9637 | /* Flush pending bus write */ | |
9638 | CSR_READ_4(sc, BWI_STATE_LO); | 9638 | CSR_READ_4(sc, BWI_STATE_LO); | |
9639 | DELAY(1); | 9639 | DELAY(1); | |
9640 | 9640 | |||
9641 | /* Enable regwin with normal clock */ | 9641 | /* Enable regwin with normal clock */ | |
9642 | state_lo = BWI_STATE_LO_CLOCK | | 9642 | state_lo = BWI_STATE_LO_CLOCK | | |
9643 | __SHIFTIN(flags, BWI_STATE_LO_FLAGS_MASK); | 9643 | __SHIFTIN(flags, BWI_STATE_LO_FLAGS_MASK); | |
9644 | CSR_WRITE_4(sc, BWI_STATE_LO, state_lo); | 9644 | CSR_WRITE_4(sc, BWI_STATE_LO, state_lo); | |
9645 | 9645 | |||
9646 | /* Flush pending bus write */ | 9646 | /* Flush pending bus write */ | |
9647 | CSR_READ_4(sc, BWI_STATE_LO); | 9647 | CSR_READ_4(sc, BWI_STATE_LO); | |
9648 | DELAY(1); | 9648 | DELAY(1); | |
9649 | } | 9649 | } | |
9650 | 9650 | |||
9651 | static void | 9651 | static void | |
9652 | bwi_set_bssid(struct bwi_softc *sc, const uint8_t *bssid) | 9652 | bwi_set_bssid(struct bwi_softc *sc, const uint8_t *bssid) | |
9653 | { | 9653 | { | |
9654 | struct ieee80211com *ic = &sc->sc_ic; | 9654 | struct ieee80211com *ic = &sc->sc_ic; | |
9655 | struct bwi_mac *mac; | 9655 | struct bwi_mac *mac; | |
9656 | struct bwi_myaddr_bssid buf; | 9656 | struct bwi_myaddr_bssid buf; | |
9657 | const uint8_t *p; | 9657 | const uint8_t *p; | |
9658 | uint32_t val; | 9658 | uint32_t val; | |
9659 | int n, i; | 9659 | int n, i; | |
9660 | 9660 | |||
9661 | KASSERT(sc->sc_cur_regwin->rw_type == BWI_REGWIN_T_MAC); | 9661 | KASSERT(sc->sc_cur_regwin->rw_type == BWI_REGWIN_T_MAC); | |
9662 | mac = (struct bwi_mac *)sc->sc_cur_regwin; | 9662 | mac = (struct bwi_mac *)sc->sc_cur_regwin; | |
9663 | 9663 | |||
9664 | bwi_set_addr_filter(sc, BWI_ADDR_FILTER_BSSID, bssid); | 9664 | bwi_set_addr_filter(sc, BWI_ADDR_FILTER_BSSID, bssid); | |
9665 | 9665 | |||
9666 | memcpy(buf.myaddr, ic->ic_myaddr, sizeof(buf.myaddr)); | 9666 | memcpy(buf.myaddr, ic->ic_myaddr, sizeof(buf.myaddr)); | |
9667 | memcpy(buf.bssid, bssid, sizeof(buf.bssid)); | 9667 | memcpy(buf.bssid, bssid, sizeof(buf.bssid)); | |
9668 | 9668 | |||
9669 | n = sizeof(buf) / sizeof(val); | 9669 | n = sizeof(buf) / sizeof(val); | |
9670 | p = (const uint8_t *)&buf; | 9670 | p = (const uint8_t *)&buf; | |
9671 | for (i = 0; i < n; ++i) { | 9671 | for (i = 0; i < n; ++i) { | |
9672 | int j; | 9672 | int j; | |
9673 | 9673 | |||
9674 | val = 0; | 9674 | val = 0; | |
9675 | for (j = 0; j < sizeof(val); ++j) | 9675 | for (j = 0; j < sizeof(val); ++j) | |
9676 | val |= ((uint32_t)(*p++)) << (j * 8); | 9676 | val |= ((uint32_t)(*p++)) << (j * 8); | |
9677 | 9677 | |||
9678 | TMPLT_WRITE_4(mac, 0x20 + (i * sizeof(val)), val); | 9678 | TMPLT_WRITE_4(mac, 0x20 + (i * sizeof(val)), val); | |
9679 | } | 9679 | } | |
9680 | } | 9680 | } | |
9681 | 9681 | |||
9682 | static void | 9682 | static void | |
9683 | bwi_updateslot(struct ifnet *ifp) | 9683 | bwi_updateslot(struct ifnet *ifp) | |
9684 | { | 9684 | { | |
9685 | struct bwi_softc *sc = ifp->if_softc; | 9685 | struct bwi_softc *sc = ifp->if_softc; | |
9686 | struct ieee80211com *ic = &sc->sc_ic; | 9686 | struct ieee80211com *ic = &sc->sc_ic; | |
9687 | struct bwi_mac *mac; | 9687 | struct bwi_mac *mac; | |
9688 | 9688 | |||
9689 | if ((ifp->if_flags & IFF_RUNNING) == 0) | 9689 | if ((ifp->if_flags & IFF_RUNNING) == 0) | |
9690 | return; | 9690 | return; | |
9691 | 9691 | |||
9692 | DPRINTF(sc, BWI_DBG_80211, "%s\n", __func__); | 9692 | DPRINTF(sc, BWI_DBG_80211, "%s\n", __func__); | |
9693 | 9693 | |||
9694 | KASSERT(sc->sc_cur_regwin->rw_type == BWI_REGWIN_T_MAC); | 9694 | KASSERT(sc->sc_cur_regwin->rw_type == BWI_REGWIN_T_MAC); | |
9695 | mac = (struct bwi_mac *)sc->sc_cur_regwin; | 9695 | mac = (struct bwi_mac *)sc->sc_cur_regwin; | |
9696 | 9696 | |||
9697 | bwi_mac_updateslot(mac, (ic->ic_flags & IEEE80211_F_SHSLOT)); | 9697 | bwi_mac_updateslot(mac, (ic->ic_flags & IEEE80211_F_SHSLOT)); | |
9698 | } | 9698 | } | |
9699 | 9699 | |||
9700 | static void | 9700 | static void | |
9701 | bwi_calibrate(void *xsc) | 9701 | bwi_calibrate(void *xsc) | |
9702 | { | 9702 | { | |
9703 | struct bwi_softc *sc = xsc; | 9703 | struct bwi_softc *sc = xsc; | |
9704 | struct ieee80211com *ic = &sc->sc_ic; | 9704 | struct ieee80211com *ic = &sc->sc_ic; | |
9705 | int s; | 9705 | int s; | |
9706 | 9706 | |||
9707 | s = splnet(); | 9707 | s = splnet(); | |
9708 | 9708 | |||
9709 | if (ic->ic_state == IEEE80211_S_RUN) { | 9709 | if (ic->ic_state == IEEE80211_S_RUN) { | |
9710 | struct bwi_mac *mac; | 9710 | struct bwi_mac *mac; | |
9711 | 9711 | |||
9712 | KASSERT(sc->sc_cur_regwin->rw_type == BWI_REGWIN_T_MAC); | 9712 | KASSERT(sc->sc_cur_regwin->rw_type == BWI_REGWIN_T_MAC); | |
9713 | mac = (struct bwi_mac *)sc->sc_cur_regwin; | 9713 | mac = (struct bwi_mac *)sc->sc_cur_regwin; | |
9714 | 9714 | |||
9715 | if (ic->ic_opmode != IEEE80211_M_MONITOR) { | 9715 | if (ic->ic_opmode != IEEE80211_M_MONITOR) { | |
9716 | bwi_mac_calibrate_txpower(mac, sc->sc_txpwrcb_type); | 9716 | bwi_mac_calibrate_txpower(mac, sc->sc_txpwrcb_type); | |
9717 | sc->sc_txpwrcb_type = BWI_TXPWR_CALIB; | 9717 | sc->sc_txpwrcb_type = BWI_TXPWR_CALIB; | |
9718 | } | 9718 | } | |
9719 | 9719 | |||
9720 | /* XXX 15 seconds */ | 9720 | /* XXX 15 seconds */ | |
9721 | callout_schedule(&sc->sc_calib_ch, hz * 15); | 9721 | callout_schedule(&sc->sc_calib_ch, hz * 15); | |
9722 | } | 9722 | } | |
9723 | 9723 | |||
9724 | splx(s); | 9724 | splx(s); | |
9725 | } | 9725 | } | |
9726 | 9726 | |||
9727 | static int | 9727 | static int | |
9728 | bwi_calc_rssi(struct bwi_softc *sc, const struct bwi_rxbuf_hdr *hdr) | 9728 | bwi_calc_rssi(struct bwi_softc *sc, const struct bwi_rxbuf_hdr *hdr) | |
9729 | { | 9729 | { | |
9730 | struct bwi_mac *mac; | 9730 | struct bwi_mac *mac; | |
9731 | 9731 | |||
9732 | KASSERT(sc->sc_cur_regwin->rw_type == BWI_REGWIN_T_MAC); | 9732 | KASSERT(sc->sc_cur_regwin->rw_type == BWI_REGWIN_T_MAC); | |
9733 | mac = (struct bwi_mac *)sc->sc_cur_regwin; | 9733 | mac = (struct bwi_mac *)sc->sc_cur_regwin; | |
9734 | 9734 | |||
9735 | return (bwi_rf_calc_rssi(mac, hdr)); | 9735 | return (bwi_rf_calc_rssi(mac, hdr)); | |
9736 | } | 9736 | } | |
9737 | 9737 | |||
9738 | bool | 9738 | bool | |
9739 | bwi_suspend(device_t dv, const pmf_qual_t *qual) | 9739 | bwi_suspend(device_t dv, const pmf_qual_t *qual) | |
9740 | { | 9740 | { | |
9741 | struct bwi_softc *sc = device_private(dv); | 9741 | struct bwi_softc *sc = device_private(dv); | |
9742 | 9742 | |||
9743 | bwi_power_off(sc, 0); | 9743 | bwi_power_off(sc, 0); | |
9744 | if (sc->sc_disable != NULL) | 9744 | if (sc->sc_disable != NULL) | |
9745 | (sc->sc_disable)(sc, 1); | 9745 | (sc->sc_disable)(sc, 1); | |
9746 | 9746 | |||
9747 | return true; | 9747 | return true; | |
9748 | } | 9748 | } | |
9749 | 9749 | |||
9750 | bool | 9750 | bool | |
9751 | bwi_resume(device_t dv, const pmf_qual_t *qual) | 9751 | bwi_resume(device_t dv, const pmf_qual_t *qual) | |
9752 | { | 9752 | { | |
9753 | struct bwi_softc *sc = device_private(dv); | 9753 | struct bwi_softc *sc = device_private(dv); | |
9754 | 9754 | |||
9755 | if (sc->sc_enable != NULL) | 9755 | if (sc->sc_enable != NULL) | |
9756 | (sc->sc_enable)(sc, 1); | 9756 | (sc->sc_enable)(sc, 1); | |
9757 | bwi_power_on(sc, 1); | 9757 | bwi_power_on(sc, 1); | |
9758 | 9758 | |||
9759 | return true; | 9759 | return true; | |
9760 | } | 9760 | } |
--- src/sys/dev/ic/cs89x0.c 2019/05/29 10:07:29 1.47
+++ src/sys/dev/ic/cs89x0.c 2020/01/29 14:14:55 1.48
@@ -1,2145 +1,2148 @@ | @@ -1,2145 +1,2148 @@ | |||
1 | /* $NetBSD: cs89x0.c,v 1.47 2019/05/29 10:07:29 msaitoh Exp $ */ | 1 | /* $NetBSD: cs89x0.c,v 1.48 2020/01/29 14:14:55 thorpej Exp $ */ | |
2 | 2 | |||
3 | /* | 3 | /* | |
4 | * Copyright (c) 2004 Christopher Gilbert | 4 | * Copyright (c) 2004 Christopher Gilbert | |
5 | * All rights reserved. | 5 | * All rights reserved. | |
6 | * | 6 | * | |
7 | * 1. Redistributions of source code must retain the above copyright | 7 | * 1. Redistributions of source code must retain the above copyright | |
8 | * notice, this list of conditions and the following disclaimer. | 8 | * notice, this list of conditions and the following disclaimer. | |
9 | * 2. Redistributions in binary form must reproduce the above copyright | 9 | * 2. Redistributions in binary form must reproduce the above copyright | |
10 | * notice, this list of conditions and the following disclaimer in the | 10 | * notice, this list of conditions and the following disclaimer in the | |
11 | * documentation and/or other materials provided with the distribution. | 11 | * documentation and/or other materials provided with the distribution. | |
12 | * 3. The name of the company nor the name of the author may be used to | 12 | * 3. The name of the company nor the name of the author may be used to | |
13 | * endorse or promote products derived from this software without specific | 13 | * endorse or promote products derived from this software without specific | |
14 | * prior written permission. | 14 | * prior written permission. | |
15 | * | 15 | * | |
16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED | 16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED | |
17 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | 17 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |
18 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | 18 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | |
19 | * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, | 19 | * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, | |
20 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | 20 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | |
22 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | 22 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
23 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | 23 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
24 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 24 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
25 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 25 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
26 | * SUCH DAMAGE. | 26 | * SUCH DAMAGE. | |
27 | */ | 27 | */ | |
28 | 28 | |||
29 | /* | 29 | /* | |
30 | * Copyright 1997 | 30 | * Copyright 1997 | |
31 | * Digital Equipment Corporation. All rights reserved. | 31 | * Digital Equipment Corporation. All rights reserved. | |
32 | * | 32 | * | |
33 | * This software is furnished under license and may be used and | 33 | * This software is furnished under license and may be used and | |
34 | * copied only in accordance with the following terms and conditions. | 34 | * copied only in accordance with the following terms and conditions. | |
35 | * Subject to these conditions, you may download, copy, install, | 35 | * Subject to these conditions, you may download, copy, install, | |
36 | * use, modify and distribute this software in source and/or binary | 36 | * use, modify and distribute this software in source and/or binary | |
37 | * form. No title or ownership is transferred hereby. | 37 | * form. No title or ownership is transferred hereby. | |
38 | * | 38 | * | |
39 | * 1) Any source code used, modified or distributed must reproduce | 39 | * 1) Any source code used, modified or distributed must reproduce | |
40 | * and retain this copyright notice and list of conditions as | 40 | * and retain this copyright notice and list of conditions as | |
41 | * they appear in the source file. | 41 | * they appear in the source file. | |
42 | * | 42 | * | |
43 | * 2) No right is granted to use any trade name, trademark, or logo of | 43 | * 2) No right is granted to use any trade name, trademark, or logo of | |
44 | * Digital Equipment Corporation. Neither the "Digital Equipment | 44 | * Digital Equipment Corporation. Neither the "Digital Equipment | |
45 | * Corporation" name nor any trademark or logo of Digital Equipment | 45 | * Corporation" name nor any trademark or logo of Digital Equipment | |
46 | * Corporation may be used to endorse or promote products derived | 46 | * Corporation may be used to endorse or promote products derived | |
47 | * from this software without the prior written permission of | 47 | * from this software without the prior written permission of | |
48 | * Digital Equipment Corporation. | 48 | * Digital Equipment Corporation. | |
49 | * | 49 | * | |
50 | * 3) This software is provided "AS-IS" and any express or implied | 50 | * 3) This software is provided "AS-IS" and any express or implied | |
51 | * warranties, including but not limited to, any implied warranties | 51 | * warranties, including but not limited to, any implied warranties | |
52 | * of merchantability, fitness for a particular purpose, or | 52 | * of merchantability, fitness for a particular purpose, or | |
53 | * non-infringement are disclaimed. In no event shall DIGITAL be | 53 | * non-infringement are disclaimed. In no event shall DIGITAL be | |
54 | * liable for any damages whatsoever, and in particular, DIGITAL | 54 | * liable for any damages whatsoever, and in particular, DIGITAL | |
55 | * shall not be liable for special, indirect, consequential, or | 55 | * shall not be liable for special, indirect, consequential, or | |
56 | * incidental damages or damages for lost profits, loss of | 56 | * incidental damages or damages for lost profits, loss of | |
57 | * revenue or loss of use, whether such damages arise in contract, | 57 | * revenue or loss of use, whether such damages arise in contract, | |
58 | * negligence, tort, under statute, in equity, at law or otherwise, | 58 | * negligence, tort, under statute, in equity, at law or otherwise, | |
59 | * even if advised of the possibility of such damage. | 59 | * even if advised of the possibility of such damage. | |
60 | */ | 60 | */ | |
61 | 61 | |||
62 | /* | 62 | /* | |
63 | **++ | 63 | **++ | |
64 | ** FACILITY | 64 | ** FACILITY | |
65 | ** | 65 | ** | |
66 | ** Device Driver for the Crystal CS8900 ISA Ethernet Controller. | 66 | ** Device Driver for the Crystal CS8900 ISA Ethernet Controller. | |
67 | ** | 67 | ** | |
68 | ** ABSTRACT | 68 | ** ABSTRACT | |
69 | ** | 69 | ** | |
70 | ** This module provides standard ethernet access for INET protocols | 70 | ** This module provides standard ethernet access for INET protocols | |
71 | ** only. | 71 | ** only. | |
72 | ** | 72 | ** | |
73 | ** AUTHORS | 73 | ** AUTHORS | |
74 | ** | 74 | ** | |
75 | ** Peter Dettori SEA - Software Engineering. | 75 | ** Peter Dettori SEA - Software Engineering. | |
76 | ** | 76 | ** | |
77 | ** CREATION DATE: | 77 | ** CREATION DATE: | |
78 | ** | 78 | ** | |
79 | ** 13-Feb-1997. | 79 | ** 13-Feb-1997. | |
80 | ** | 80 | ** | |
81 | ** MODIFICATION HISTORY (Digital): | 81 | ** MODIFICATION HISTORY (Digital): | |
82 | ** | 82 | ** | |
83 | ** Revision 1.27 1998/01/20 17:59:40 cgd | 83 | ** Revision 1.27 1998/01/20 17:59:40 cgd | |
84 | ** update for moved headers | 84 | ** update for moved headers | |
85 | ** | 85 | ** | |
86 | ** Revision 1.26 1998/01/12 19:29:36 cgd | 86 | ** Revision 1.26 1998/01/12 19:29:36 cgd | |
87 | ** use arm32/isa versions of isadma code. | 87 | ** use arm32/isa versions of isadma code. | |
88 | ** | 88 | ** | |
89 | ** Revision 1.25 1997/12/12 01:35:27 cgd | 89 | ** Revision 1.25 1997/12/12 01:35:27 cgd | |
90 | ** convert to use new arp code (from Brini) | 90 | ** convert to use new arp code (from Brini) | |
91 | ** | 91 | ** | |
92 | ** Revision 1.24 1997/12/10 22:31:56 cgd | 92 | ** Revision 1.24 1997/12/10 22:31:56 cgd | |
93 | ** trim some fat (get rid of ability to explicitly supply enet addr, since | 93 | ** trim some fat (get rid of ability to explicitly supply enet addr, since | |
94 | ** it was never used and added a bunch of code which really doesn't belong in | 94 | ** it was never used and added a bunch of code which really doesn't belong in | |
95 | ** an enet driver), and clean up slightly. | 95 | ** an enet driver), and clean up slightly. | |
96 | ** | 96 | ** | |
97 | ** Revision 1.23 1997/10/06 16:42:12 cgd | 97 | ** Revision 1.23 1997/10/06 16:42:12 cgd | |
98 | ** copyright notices | 98 | ** copyright notices | |
99 | ** | 99 | ** | |
100 | ** Revision 1.22 1997/06/20 19:38:01 chaiken | 100 | ** Revision 1.22 1997/06/20 19:38:01 chaiken | |
101 | ** fixes some smartcard problems | 101 | ** fixes some smartcard problems | |
102 | ** | 102 | ** | |
103 | ** Revision 1.21 1997/06/10 02:56:20 grohn | 103 | ** Revision 1.21 1997/06/10 02:56:20 grohn | |
104 | ** Added call to ledNetActive | 104 | ** Added call to ledNetActive | |
105 | ** | 105 | ** | |
106 | ** Revision 1.20 1997/06/05 00:47:06 dettori | 106 | ** Revision 1.20 1997/06/05 00:47:06 dettori | |
107 | ** Changed cs_process_rx_dma to reset and re-initialise the | 107 | ** Changed cs_process_rx_dma to reset and re-initialise the | |
108 | ** ethernet chip when DMA gets out of sync, or mbufs | 108 | ** ethernet chip when DMA gets out of sync, or mbufs | |
109 | ** can't be allocated. | 109 | ** can't be allocated. | |
110 | ** | 110 | ** | |
111 | ** Revision 1.19 1997/06/03 03:09:58 dettori | 111 | ** Revision 1.19 1997/06/03 03:09:58 dettori | |
112 | ** Turn off sc_txbusy flag when a transmit underrun | 112 | ** Turn off sc_txbusy flag when a transmit underrun | |
113 | ** occurs. | 113 | ** occurs. | |
114 | ** | 114 | ** | |
115 | ** Revision 1.18 1997/06/02 00:04:35 dettori | 115 | ** Revision 1.18 1997/06/02 00:04:35 dettori | |
116 | ** redefined the transmit table to get around the nfs_timer bug while we are | 116 | ** redefined the transmit table to get around the nfs_timer bug while we are | |
117 | ** looking into it further. | 117 | ** looking into it further. | |
118 | ** | 118 | ** | |
119 | ** Also changed interrupts from EDGE to LEVEL. | 119 | ** Also changed interrupts from EDGE to LEVEL. | |
120 | ** | 120 | ** | |
121 | ** Revision 1.17 1997/05/27 23:31:01 dettori | 121 | ** Revision 1.17 1997/05/27 23:31:01 dettori | |
122 | ** Pulled out changes to DMAMODE defines. | 122 | ** Pulled out changes to DMAMODE defines. | |
123 | ** | 123 | ** | |
124 | ** Revision 1.16 1997/05/23 04:25:16 cgd | 124 | ** Revision 1.16 1997/05/23 04:25:16 cgd | |
125 | ** reformat log so it fits in 80cols | 125 | ** reformat log so it fits in 80cols | |
126 | ** | 126 | ** | |
127 | ** Revision 1.15 1997/05/23 04:22:18 cgd | 127 | ** Revision 1.15 1997/05/23 04:22:18 cgd | |
128 | ** remove the existing copyright notice (which Peter Dettori indicated | 128 | ** remove the existing copyright notice (which Peter Dettori indicated | |
129 | ** was incorrect, copied from an existing NetBSD file only so that the | 129 | ** was incorrect, copied from an existing NetBSD file only so that the | |
130 | ** file would have a copyright notice on it, and which he'd intended to | 130 | ** file would have a copyright notice on it, and which he'd intended to | |
131 | ** replace). Replace it with a Digital copyright notice, cloned from | 131 | ** replace). Replace it with a Digital copyright notice, cloned from | |
132 | ** ess.c. It's not really correct either (it indicates that the source | 132 | ** ess.c. It's not really correct either (it indicates that the source | |
133 | ** is Digital confidential!), but is better than nothing and more | 133 | ** is Digital confidential!), but is better than nothing and more | |
134 | ** correct than what was there before. | 134 | ** correct than what was there before. | |
135 | ** | 135 | ** | |
136 | ** Revision 1.14 1997/05/23 04:12:50 cgd | 136 | ** Revision 1.14 1997/05/23 04:12:50 cgd | |
137 | ** use an adaptive transmit start algorithm: start by telling the chip | 137 | ** use an adaptive transmit start algorithm: start by telling the chip | |
138 | ** to start transmitting after 381 bytes have been fed to it. if that | 138 | ** to start transmitting after 381 bytes have been fed to it. if that | |
139 | ** gets transmit underruns, ramp down to 1021 bytes then "whole | 139 | ** gets transmit underruns, ramp down to 1021 bytes then "whole | |
140 | ** packet." If successful at a given level for a while, try the next | 140 | ** packet." If successful at a given level for a while, try the next | |
141 | ** more agressive level. This code doesn't ever try to start | 141 | ** more agressive level. This code doesn't ever try to start | |
142 | ** transmitting after 5 bytes have been sent to the NIC, because | 142 | ** transmitting after 5 bytes have been sent to the NIC, because | |
143 | ** that underruns rather regularly. The back-off and ramp-up mechanism | 143 | ** that underruns rather regularly. The back-off and ramp-up mechanism | |
144 | ** could probably be tuned a little bit, but this works well enough to | 144 | ** could probably be tuned a little bit, but this works well enough to | |
145 | ** support > 1MB/s transmit rates on a clear ethernet (which is about | 145 | ** support > 1MB/s transmit rates on a clear ethernet (which is about | |
146 | ** 20-25% better than the driver had previously been getting). | 146 | ** 20-25% better than the driver had previously been getting). | |
147 | ** | 147 | ** | |
148 | ** Revision 1.13 1997/05/22 21:06:54 cgd | 148 | ** Revision 1.13 1997/05/22 21:06:54 cgd | |
149 | ** redo cs_copy_tx_frame() from scratch. It had a fatal flaw: it was blindly | 149 | ** redo cs_copy_tx_frame() from scratch. It had a fatal flaw: it was blindly | |
150 | ** casting from uint8_t * to uint16_t * without worrying about alignment | 150 | ** casting from uint8_t * to uint16_t * without worrying about alignment | |
151 | ** issues. This would cause bogus data to be spit out for mbufs with | 151 | ** issues. This would cause bogus data to be spit out for mbufs with | |
152 | ** misaligned data. For instance, it caused the following bits to appear | 152 | ** misaligned data. For instance, it caused the following bits to appear | |
153 | ** on the wire: | 153 | ** on the wire: | |
154 | ** ... etBND 1S2C .SHA(K) R ... | 154 | ** ... etBND 1S2C .SHA(K) R ... | |
155 | ** 11112222333344445555 | 155 | ** 11112222333344445555 | |
156 | ** which should have appeared as: | 156 | ** which should have appeared as: | |
157 | ** ... NetBSD 1.2C (SHARK) ... | 157 | ** ... NetBSD 1.2C (SHARK) ... | |
158 | ** 11112222333344445555 | 158 | ** 11112222333344445555 | |
159 | ** Note the apparent 'rotate' of the bytes in the word, which was due to | 159 | ** Note the apparent 'rotate' of the bytes in the word, which was due to | |
160 | ** incorrect unaligned accesses. This data corruption was the cause of | 160 | ** incorrect unaligned accesses. This data corruption was the cause of | |
161 | ** incoming telnet/rlogin hangs. | 161 | ** incoming telnet/rlogin hangs. | |
162 | ** | 162 | ** | |
163 | ** Revision 1.12 1997/05/22 01:55:32 cgd | 163 | ** Revision 1.12 1997/05/22 01:55:32 cgd | |
164 | ** reformat log so it fits in 80cols | 164 | ** reformat log so it fits in 80cols | |
165 | ** | 165 | ** | |
166 | ** Revision 1.11 1997/05/22 01:50:27 cgd | 166 | ** Revision 1.11 1997/05/22 01:50:27 cgd | |
167 | ** * enable input packet address checking in the BPF+IFF_PROMISCUOUS case, | 167 | ** * enable input packet address checking in the BPF+IFF_PROMISCUOUS case, | |
168 | ** so packets aimed at other hosts don't get sent to ether_input(). | 168 | ** so packets aimed at other hosts don't get sent to ether_input(). | |
169 | ** * Add a static const char *rcsid initialized with an RCS Id tag, so that | 169 | ** * Add a static const char *rcsid initialized with an RCS Id tag, so that | |
170 | ** you can easily tell (`strings`) what version of the driver is in your | 170 | ** you can easily tell (`strings`) what version of the driver is in your | |
171 | ** kernel binary. | 171 | ** kernel binary. | |
172 | ** * get rid of ether_cmp(). It was inconsistently used, not necessarily | 172 | ** * get rid of ether_cmp(). It was inconsistently used, not necessarily | |
173 | ** safe, and not really a performance win anyway. (It was only used when | 173 | ** safe, and not really a performance win anyway. (It was only used when | |
174 | ** setting up the multicast logical address filter, which is an | 174 | ** setting up the multicast logical address filter, which is an | |
175 | ** infrequent event. It could have been used in the IFF_PROMISCUOUS | 175 | ** infrequent event. It could have been used in the IFF_PROMISCUOUS | |
176 | ** address check above, but the benefit of it vs. memcmp would be | 176 | ** address check above, but the benefit of it vs. memcmp would be | |
177 | ** inconsequential, there.) Use memcmp() instead. | 177 | ** inconsequential, there.) Use memcmp() instead. | |
178 | ** * restructure csStartOuput to avoid the following bugs in the case where | 178 | ** * restructure csStartOuput to avoid the following bugs in the case where | |
179 | ** txWait was being set: | 179 | ** txWait was being set: | |
180 | ** * it would accidentally drop the outgoing packet if told to wait | 180 | ** * it would accidentally drop the outgoing packet if told to wait | |
181 | ** but the outgoing packet queue was empty. | 181 | ** but the outgoing packet queue was empty. | |
182 | ** * it would bpf_mtap() the outgoing packet multiple times (once for | 182 | ** * it would bpf_mtap() the outgoing packet multiple times (once for | |
183 | ** each time it was told to wait), and would also recalculate | 183 | ** each time it was told to wait), and would also recalculate | |
184 | ** the length of the outgoing packet each time it was told to | 184 | ** the length of the outgoing packet each time it was told to | |
185 | ** wait. | 185 | ** wait. | |
186 | ** While there, rename txWait to txLoop, since with the new structure of | 186 | ** While there, rename txWait to txLoop, since with the new structure of | |
187 | ** the code, the latter name makes more sense. | 187 | ** the code, the latter name makes more sense. | |
188 | ** | 188 | ** | |
189 | ** Revision 1.10 1997/05/19 02:03:20 cgd | 189 | ** Revision 1.10 1997/05/19 02:03:20 cgd | |
190 | ** Set RX_CTL in cs_set_ladr_filt(), rather than cs_initChip(). cs_initChip() | 190 | ** Set RX_CTL in cs_set_ladr_filt(), rather than cs_initChip(). cs_initChip() | |
191 | ** is the only caller of cs_set_ladr_filt(), and always calls it, so this | 191 | ** is the only caller of cs_set_ladr_filt(), and always calls it, so this | |
192 | ** ends up being logically the same. In cs_set_ladr_filt(), if IFF_PROMISC | 192 | ** ends up being logically the same. In cs_set_ladr_filt(), if IFF_PROMISC | |
193 | ** is set, enable promiscuous mode (and set IFF_ALLMULTI), otherwise behave | 193 | ** is set, enable promiscuous mode (and set IFF_ALLMULTI), otherwise behave | |
194 | ** as before. | 194 | ** as before. | |
195 | ** | 195 | ** | |
196 | ** Revision 1.9 1997/05/19 01:45:37 cgd | 196 | ** Revision 1.9 1997/05/19 01:45:37 cgd | |
197 | ** create a new function, cs_ether_input(), which does received-packet | 197 | ** create a new function, cs_ether_input(), which does received-packet | |
198 | ** BPF and ether_input processing. This code used to be in three places, | 198 | ** BPF and ether_input processing. This code used to be in three places, | |
199 | ** and centralizing it will make adding IFF_PROMISC support much easier. | 199 | ** and centralizing it will make adding IFF_PROMISC support much easier. | |
200 | ** Also, in cs_copy_tx_frame(), put it some (currently disabled) code to | 200 | ** Also, in cs_copy_tx_frame(), put it some (currently disabled) code to | |
201 | ** do copies with bus_space_write_region_2(). It's more correct, and | 201 | ** do copies with bus_space_write_region_2(). It's more correct, and | |
202 | ** potentially more efficient. That function needs to be gutted (to | 202 | ** potentially more efficient. That function needs to be gutted (to | |
203 | ** deal properly with alignment issues, which it currently does wrong), | 203 | ** deal properly with alignment issues, which it currently does wrong), | |
204 | ** however, and the change doesn't gain much, so there's no point in | 204 | ** however, and the change doesn't gain much, so there's no point in | |
205 | ** enabling it now. | 205 | ** enabling it now. | |
206 | ** | 206 | ** | |
207 | ** Revision 1.8 1997/05/19 01:17:10 cgd | 207 | ** Revision 1.8 1997/05/19 01:17:10 cgd | |
208 | ** fix a comment re: the setting of the TxConfig register. Clean up | 208 | ** fix a comment re: the setting of the TxConfig register. Clean up | |
209 | ** interface counter maintenance (make it use standard idiom). | 209 | ** interface counter maintenance (make it use standard idiom). | |
210 | ** | 210 | ** | |
211 | **-- | 211 | **-- | |
212 | */ | 212 | */ | |
213 | 213 | |||
214 | #include <sys/cdefs.h> | 214 | #include <sys/cdefs.h> | |
215 | __KERNEL_RCSID(0, "$NetBSD: cs89x0.c,v 1.47 2019/05/29 10:07:29 msaitoh Exp $"); | 215 | __KERNEL_RCSID(0, "$NetBSD: cs89x0.c,v 1.48 2020/01/29 14:14:55 thorpej Exp $"); | |
216 | 216 | |||
217 | #include "opt_inet.h" | 217 | #include "opt_inet.h" | |
218 | 218 | |||
219 | #include <sys/param.h> | 219 | #include <sys/param.h> | |
220 | #include <sys/systm.h> | 220 | #include <sys/systm.h> | |
221 | #include <sys/mbuf.h> | 221 | #include <sys/mbuf.h> | |
222 | #include <sys/syslog.h> | 222 | #include <sys/syslog.h> | |
223 | #include <sys/socket.h> | 223 | #include <sys/socket.h> | |
224 | #include <sys/device.h> | 224 | #include <sys/device.h> | |
225 | #include <sys/malloc.h> | 225 | #include <sys/malloc.h> | |
226 | #include <sys/ioctl.h> | 226 | #include <sys/ioctl.h> | |
227 | #include <sys/errno.h> | 227 | #include <sys/errno.h> | |
228 | #include <sys/bus.h> | 228 | #include <sys/bus.h> | |
229 | #include <sys/intr.h> | 229 | #include <sys/intr.h> | |
230 | #include <sys/rndsource.h> | 230 | #include <sys/rndsource.h> | |
231 | 231 | |||
232 | #include <net/if.h> | 232 | #include <net/if.h> | |
233 | #include <net/if_ether.h> | 233 | #include <net/if_ether.h> | |
234 | #include <net/if_media.h> | 234 | #include <net/if_media.h> | |
235 | #include <net/bpf.h> | 235 | #include <net/bpf.h> | |
236 | 236 | |||
237 | #ifdef INET | 237 | #ifdef INET | |
238 | #include <netinet/in.h> | 238 | #include <netinet/in.h> | |
239 | #include <netinet/if_inarp.h> | 239 | #include <netinet/if_inarp.h> | |
240 | #endif | 240 | #endif | |
241 | 241 | |||
242 | #include <dev/ic/cs89x0reg.h> | 242 | #include <dev/ic/cs89x0reg.h> | |
243 | #include <dev/ic/cs89x0var.h> | 243 | #include <dev/ic/cs89x0var.h> | |
244 | 244 | |||
245 | #ifdef SHARK | 245 | #ifdef SHARK | |
246 | #include <shark/shark/sequoia.h> | 246 | #include <shark/shark/sequoia.h> | |
247 | #endif | 247 | #endif | |
248 | 248 | |||
249 | /* | 249 | /* | |
250 | * MACRO DEFINITIONS | 250 | * MACRO DEFINITIONS | |
251 | */ | 251 | */ | |
252 | #define CS_OUTPUT_LOOP_MAX 100 /* max times round notorious tx loop */ | 252 | #define CS_OUTPUT_LOOP_MAX 100 /* max times round notorious tx loop */ | |
253 | 253 | |||
254 | /* | 254 | /* | |
255 | * FUNCTION PROTOTYPES | 255 | * FUNCTION PROTOTYPES | |
256 | */ | 256 | */ | |
257 | static void cs_get_default_media(struct cs_softc *); | 257 | static void cs_get_default_media(struct cs_softc *); | |
258 | static int cs_get_params(struct cs_softc *); | 258 | static int cs_get_params(struct cs_softc *); | |
259 | static int cs_get_enaddr(struct cs_softc *); | 259 | static int cs_get_enaddr(struct cs_softc *); | |
260 | static int cs_reset_chip(struct cs_softc *); | 260 | static int cs_reset_chip(struct cs_softc *); | |
261 | static void cs_reset(struct cs_softc *); | 261 | static void cs_reset(struct cs_softc *); | |
262 | static int cs_ioctl(struct ifnet *, u_long, void *); | 262 | static int cs_ioctl(struct ifnet *, u_long, void *); | |
263 | static void cs_initChip(struct cs_softc *); | 263 | static void cs_initChip(struct cs_softc *); | |
264 | static void cs_buffer_event(struct cs_softc *, uint16_t); | 264 | static void cs_buffer_event(struct cs_softc *, uint16_t); | |
265 | static void cs_transmit_event(struct cs_softc *, uint16_t); | 265 | static void cs_transmit_event(struct cs_softc *, uint16_t); | |
266 | static void cs_receive_event(struct cs_softc *, uint16_t); | 266 | static void cs_receive_event(struct cs_softc *, uint16_t); | |
267 | static void cs_process_receive(struct cs_softc *); | 267 | static void cs_process_receive(struct cs_softc *); | |
268 | static void cs_process_rx_early(struct cs_softc *); | 268 | static void cs_process_rx_early(struct cs_softc *); | |
269 | static void cs_start_output(struct ifnet *); | 269 | static void cs_start_output(struct ifnet *); | |
270 | static void cs_copy_tx_frame(struct cs_softc *, struct mbuf *); | 270 | static void cs_copy_tx_frame(struct cs_softc *, struct mbuf *); | |
271 | static void cs_set_ladr_filt(struct cs_softc *, struct ethercom *); | 271 | static void cs_set_ladr_filt(struct cs_softc *, struct ethercom *); | |
272 | static uint16_t cs_hash_index(char *); | 272 | static uint16_t cs_hash_index(char *); | |
273 | static void cs_counter_event(struct cs_softc *, uint16_t); | 273 | static void cs_counter_event(struct cs_softc *, uint16_t); | |
274 | 274 | |||
275 | static int cs_mediachange(struct ifnet *); | 275 | static int cs_mediachange(struct ifnet *); | |
276 | static void cs_mediastatus(struct ifnet *, struct ifmediareq *); | 276 | static void cs_mediastatus(struct ifnet *, struct ifmediareq *); | |
277 | 277 | |||
278 | static bool cs_shutdown(device_t, int); | 278 | static bool cs_shutdown(device_t, int); | |
279 | static int cs_enable(struct cs_softc *); | 279 | static int cs_enable(struct cs_softc *); | |
280 | static void cs_disable(struct cs_softc *); | 280 | static void cs_disable(struct cs_softc *); | |
281 | static void cs_stop(struct ifnet *, int); | 281 | static void cs_stop(struct ifnet *, int); | |
282 | static int cs_scan_eeprom(struct cs_softc *); | 282 | static int cs_scan_eeprom(struct cs_softc *); | |
283 | static int cs_read_pktpg_from_eeprom(struct cs_softc *, int, uint16_t *); | 283 | static int cs_read_pktpg_from_eeprom(struct cs_softc *, int, uint16_t *); | |
284 | 284 | |||
285 | 285 | |||
286 | /* | 286 | /* | |
287 | * GLOBAL DECLARATIONS | 287 | * GLOBAL DECLARATIONS | |
288 | */ | 288 | */ | |
289 | 289 | |||
290 | /* | 290 | /* | |
291 | * Xmit-early table. | 291 | * Xmit-early table. | |
292 | * | 292 | * | |
293 | * To get better performance, we tell the chip to start packet | 293 | * To get better performance, we tell the chip to start packet | |
294 | * transmission before the whole packet is copied to the chip. | 294 | * transmission before the whole packet is copied to the chip. | |
295 | * However, this can fail under load. When it fails, we back off | 295 | * However, this can fail under load. When it fails, we back off | |
296 | * to a safer setting for a little while. | 296 | * to a safer setting for a little while. | |
297 | * | 297 | * | |
298 | * txcmd is the value of txcmd used to indicate when to start transmission. | 298 | * txcmd is the value of txcmd used to indicate when to start transmission. | |
299 | * better is the next 'better' state in the table. | 299 | * better is the next 'better' state in the table. | |
300 | * better_count is the number of output packets before transition to the | 300 | * better_count is the number of output packets before transition to the | |
301 | * better state. | 301 | * better state. | |
302 | * worse is the next 'worse' state in the table. | 302 | * worse is the next 'worse' state in the table. | |
303 | * | 303 | * | |
304 | * Transition to the next worse state happens automatically when a | 304 | * Transition to the next worse state happens automatically when a | |
305 | * transmittion underrun occurs. | 305 | * transmittion underrun occurs. | |
306 | */ | 306 | */ | |
307 | struct cs_xmit_early { | 307 | struct cs_xmit_early { | |
308 | uint16_t txcmd; | 308 | uint16_t txcmd; | |
309 | int better; | 309 | int better; | |
310 | int better_count; | 310 | int better_count; | |
311 | int worse; | 311 | int worse; | |
312 | } cs_xmit_early_table[3] = { | 312 | } cs_xmit_early_table[3] = { | |
313 | { TX_CMD_START_381, 0, INT_MAX, 1, }, | 313 | { TX_CMD_START_381, 0, INT_MAX, 1, }, | |
314 | { TX_CMD_START_1021, 0, 50000, 2, }, | 314 | { TX_CMD_START_1021, 0, 50000, 2, }, | |
315 | { TX_CMD_START_ALL, 1, 5000, 2, }, | 315 | { TX_CMD_START_ALL, 1, 5000, 2, }, | |
316 | }; | 316 | }; | |
317 | 317 | |||
318 | int cs_default_media[] = { | 318 | int cs_default_media[] = { | |
319 | IFM_ETHER | IFM_10_2, | 319 | IFM_ETHER | IFM_10_2, | |
320 | IFM_ETHER | IFM_10_5, | 320 | IFM_ETHER | IFM_10_5, | |
321 | IFM_ETHER | IFM_10_T, | 321 | IFM_ETHER | IFM_10_T, | |
322 | IFM_ETHER | IFM_10_T | IFM_FDX, | 322 | IFM_ETHER | IFM_10_T | IFM_FDX, | |
323 | }; | 323 | }; | |
324 | int cs_default_nmedia = __arraycount(cs_default_media); | 324 | int cs_default_nmedia = __arraycount(cs_default_media); | |
325 | 325 | |||
326 | int | 326 | int | |
327 | cs_attach(struct cs_softc *sc, uint8_t *enaddr, int *media, | 327 | cs_attach(struct cs_softc *sc, uint8_t *enaddr, int *media, | |
328 | int nmedia, int defmedia) | 328 | int nmedia, int defmedia) | |
329 | { | 329 | { | |
330 | struct ifnet *ifp = &sc->sc_ethercom.ec_if; | 330 | struct ifnet *ifp = &sc->sc_ethercom.ec_if; | |
331 | const char *chipname, *medname; | 331 | const char *chipname, *medname; | |
332 | uint16_t reg; | 332 | uint16_t reg; | |
333 | int i; | 333 | int i; | |
334 | 334 | |||
335 | /* Start out in IO mode */ | 335 | /* Start out in IO mode */ | |
336 | sc->sc_memorymode = FALSE; | 336 | sc->sc_memorymode = FALSE; | |
337 | 337 | |||
338 | /* Make sure we're right */ | 338 | /* Make sure we're right */ | |
339 | for (i = 0; i < 10000; i++) { | 339 | for (i = 0; i < 10000; i++) { | |
340 | reg = CS_READ_PACKET_PAGE(sc, PKTPG_EISA_NUM); | 340 | reg = CS_READ_PACKET_PAGE(sc, PKTPG_EISA_NUM); | |
341 | if (reg == EISA_NUM_CRYSTAL) | 341 | if (reg == EISA_NUM_CRYSTAL) | |
342 | break; | 342 | break; | |
343 | } | 343 | } | |
344 | if (i == 10000) { | 344 | if (i == 10000) { | |
345 | aprint_error_dev(sc->sc_dev, "wrong id(0x%x)\n", reg); | 345 | aprint_error_dev(sc->sc_dev, "wrong id(0x%x)\n", reg); | |
346 | return 1; /* XXX should panic? */ | 346 | return 1; /* XXX should panic? */ | |
347 | } | 347 | } | |
348 | 348 | |||
349 | reg = CS_READ_PACKET_PAGE(sc, PKTPG_PRODUCT_ID); | 349 | reg = CS_READ_PACKET_PAGE(sc, PKTPG_PRODUCT_ID); | |
350 | sc->sc_prodid = reg & PROD_ID_MASK; | 350 | sc->sc_prodid = reg & PROD_ID_MASK; | |
351 | sc->sc_prodrev = (reg & PROD_REV_MASK) >> 8; | 351 | sc->sc_prodrev = (reg & PROD_REV_MASK) >> 8; | |
352 | 352 | |||
353 | switch (sc->sc_prodid) { | 353 | switch (sc->sc_prodid) { | |
354 | case PROD_ID_CS8900: | 354 | case PROD_ID_CS8900: | |
355 | chipname = "CS8900"; | 355 | chipname = "CS8900"; | |
356 | break; | 356 | break; | |
357 | case PROD_ID_CS8920: | 357 | case PROD_ID_CS8920: | |
358 | chipname = "CS8920"; | 358 | chipname = "CS8920"; | |
359 | break; | 359 | break; | |
360 | case PROD_ID_CS8920M: | 360 | case PROD_ID_CS8920M: | |
361 | chipname = "CS8920M"; | 361 | chipname = "CS8920M"; | |
362 | break; | 362 | break; | |
363 | default: | 363 | default: | |
364 | panic("cs_attach: impossible"); | 364 | panic("cs_attach: impossible"); | |
365 | } | 365 | } | |
366 | 366 | |||
367 | /* | 367 | /* | |
368 | * The first thing to do is check that the mbuf cluster size is | 368 | * The first thing to do is check that the mbuf cluster size is | |
369 | * greater than the MTU for an ethernet frame. The code depends on | 369 | * greater than the MTU for an ethernet frame. The code depends on | |
370 | * this and to port this to a OS where this was not the case would | 370 | * this and to port this to a OS where this was not the case would | |
371 | * not be straightforward. | 371 | * not be straightforward. | |
372 | * | 372 | * | |
373 | * We need 1 byte spare because our packet read loop can overrun. | 373 | * We need 1 byte spare because our packet read loop can overrun. | |
374 | * and we may need pad bytes to align ip header. | 374 | * and we may need pad bytes to align ip header. | |
375 | */ | 375 | */ | |
376 | if (MCLBYTES < ETHER_MAX_LEN + 1 + ALIGN(sizeof(struct ether_header)) | 376 | if (MCLBYTES < ETHER_MAX_LEN + 1 + ALIGN(sizeof(struct ether_header)) | |
377 | - sizeof(struct ether_header)) { | 377 | - sizeof(struct ether_header)) { | |
378 | printf("%s: MCLBYTES too small for Ethernet frame\n", | 378 | printf("%s: MCLBYTES too small for Ethernet frame\n", | |
379 | device_xname(sc->sc_dev)); | 379 | device_xname(sc->sc_dev)); | |
380 | return 1; | 380 | return 1; | |
381 | } | 381 | } | |
382 | 382 | |||
383 | /* Start out not transmitting */ | 383 | /* Start out not transmitting */ | |
384 | sc->sc_txbusy = FALSE; | 384 | sc->sc_txbusy = FALSE; | |
385 | 385 | |||
386 | /* Set up early transmit threshhold */ | 386 | /* Set up early transmit threshhold */ | |
387 | sc->sc_xe_ent = 0; | 387 | sc->sc_xe_ent = 0; | |
388 | sc->sc_xe_togo = cs_xmit_early_table[sc->sc_xe_ent].better_count; | 388 | sc->sc_xe_togo = cs_xmit_early_table[sc->sc_xe_ent].better_count; | |
389 | 389 | |||
390 | /* Initialize ifnet structure. */ | 390 | /* Initialize ifnet structure. */ | |
391 | strlcpy(ifp->if_xname, device_xname(sc->sc_dev), IFNAMSIZ); | 391 | strlcpy(ifp->if_xname, device_xname(sc->sc_dev), IFNAMSIZ); | |
392 | ifp->if_softc = sc; | 392 | ifp->if_softc = sc; | |
393 | ifp->if_start = cs_start_output; | 393 | ifp->if_start = cs_start_output; | |
394 | ifp->if_init = cs_init; | 394 | ifp->if_init = cs_init; | |
395 | ifp->if_ioctl = cs_ioctl; | 395 | ifp->if_ioctl = cs_ioctl; | |
396 | ifp->if_stop = cs_stop; | 396 | ifp->if_stop = cs_stop; | |
397 | ifp->if_watchdog = NULL; /* No watchdog at this stage */ | 397 | ifp->if_watchdog = NULL; /* No watchdog at this stage */ | |
398 | ifp->if_flags = IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST; | 398 | ifp->if_flags = IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST; | |
399 | IFQ_SET_READY(&ifp->if_snd); | 399 | IFQ_SET_READY(&ifp->if_snd); | |
400 | 400 | |||
401 | /* Initialize ifmedia structures. */ | 401 | /* Initialize ifmedia structures. */ | |
402 | sc->sc_ethercom.ec_ifmedia = &sc->sc_media; | 402 | sc->sc_ethercom.ec_ifmedia = &sc->sc_media; | |
403 | ifmedia_init(&sc->sc_media, 0, cs_mediachange, cs_mediastatus); | 403 | ifmedia_init(&sc->sc_media, 0, cs_mediachange, cs_mediastatus); | |
404 | 404 | |||
405 | if (media != NULL) { | 405 | if (media != NULL) { | |
406 | for (i = 0; i < nmedia; i++) | 406 | for (i = 0; i < nmedia; i++) | |
407 | ifmedia_add(&sc->sc_media, media[i], 0, NULL); | 407 | ifmedia_add(&sc->sc_media, media[i], 0, NULL); | |
408 | ifmedia_set(&sc->sc_media, defmedia); | 408 | ifmedia_set(&sc->sc_media, defmedia); | |
409 | } else { | 409 | } else { | |
410 | for (i = 0; i < cs_default_nmedia; i++) | 410 | for (i = 0; i < cs_default_nmedia; i++) | |
411 | ifmedia_add(&sc->sc_media, cs_default_media[i], | 411 | ifmedia_add(&sc->sc_media, cs_default_media[i], | |
412 | 0, NULL); | 412 | 0, NULL); | |
413 | cs_get_default_media(sc); | 413 | cs_get_default_media(sc); | |
414 | } | 414 | } | |
415 | 415 | |||
416 | if (sc->sc_cfgflags & CFGFLG_PARSE_EEPROM) { | 416 | if (sc->sc_cfgflags & CFGFLG_PARSE_EEPROM) { | |
417 | if (cs_scan_eeprom(sc) == CS_ERROR) { | 417 | if (cs_scan_eeprom(sc) == CS_ERROR) { | |
418 | /* | 418 | /* | |
419 | * Failed to scan the eeprom, pretend there isn't an | 419 | * Failed to scan the eeprom, pretend there isn't an | |
420 | * eeprom | 420 | * eeprom | |
421 | */ | 421 | */ | |
422 | aprint_error_dev(sc->sc_dev, | 422 | aprint_error_dev(sc->sc_dev, | |
423 | "unable to scan EEPROM\n"); | 423 | "unable to scan EEPROM\n"); | |
424 | sc->sc_cfgflags |= CFGFLG_NOT_EEPROM; | 424 | sc->sc_cfgflags |= CFGFLG_NOT_EEPROM; | |
425 | } | 425 | } | |
426 | } | 426 | } | |
427 | 427 | |||
428 | if ((sc->sc_cfgflags & CFGFLG_NOT_EEPROM) == 0) { | 428 | if ((sc->sc_cfgflags & CFGFLG_NOT_EEPROM) == 0) { | |
429 | /* Get parameters from the EEPROM */ | 429 | /* Get parameters from the EEPROM */ | |
430 | if (cs_get_params(sc) == CS_ERROR) { | 430 | if (cs_get_params(sc) == CS_ERROR) { | |
431 | aprint_error_dev(sc->sc_dev, | 431 | aprint_error_dev(sc->sc_dev, | |
432 | "unable to get settings from EEPROM\n"); | 432 | "unable to get settings from EEPROM\n"); | |
433 | return 1; | 433 | return 1; | |
434 | } | 434 | } | |
435 | } | 435 | } | |
436 | 436 | |||
437 | if (enaddr != NULL) | 437 | if (enaddr != NULL) | |
438 | memcpy(sc->sc_enaddr, enaddr, sizeof(sc->sc_enaddr)); | 438 | memcpy(sc->sc_enaddr, enaddr, sizeof(sc->sc_enaddr)); | |
439 | else if ((sc->sc_cfgflags & CFGFLG_NOT_EEPROM) == 0) { | 439 | else if ((sc->sc_cfgflags & CFGFLG_NOT_EEPROM) == 0) { | |
440 | /* Get and store the Ethernet address */ | 440 | /* Get and store the Ethernet address */ | |
441 | if (cs_get_enaddr(sc) == CS_ERROR) { | 441 | if (cs_get_enaddr(sc) == CS_ERROR) { | |
442 | aprint_error_dev(sc->sc_dev, | 442 | aprint_error_dev(sc->sc_dev, | |
443 | "unable to read Ethernet address\n"); | 443 | "unable to read Ethernet address\n"); | |
444 | return 1; | 444 | return 1; | |
445 | } | 445 | } | |
446 | } else { | 446 | } else { | |
447 | #if 1 | 447 | #if 1 | |
448 | int j; | 448 | int j; | |
449 | uint v; | 449 | uint v; | |
450 | 450 | |||
451 | for (j = 0; j < 6; j += 2) { | 451 | for (j = 0; j < 6; j += 2) { | |
452 | v = CS_READ_PACKET_PAGE(sc, PKTPG_IND_ADDR + j); | 452 | v = CS_READ_PACKET_PAGE(sc, PKTPG_IND_ADDR + j); | |
453 | sc->sc_enaddr[j + 0] = v; | 453 | sc->sc_enaddr[j + 0] = v; | |
454 | sc->sc_enaddr[j + 1] = v >> 8; | 454 | sc->sc_enaddr[j + 1] = v >> 8; | |
455 | } | 455 | } | |
456 | #else | 456 | #else | |
457 | printf("%s: no Ethernet address!\n", device_xname(sc->sc_dev)); | 457 | printf("%s: no Ethernet address!\n", device_xname(sc->sc_dev)); | |
458 | return 1; | 458 | return 1; | |
459 | #endif | 459 | #endif | |
460 | } | 460 | } | |
461 | 461 | |||
462 | switch (IFM_SUBTYPE(sc->sc_media.ifm_cur->ifm_media)) { | 462 | switch (IFM_SUBTYPE(sc->sc_media.ifm_cur->ifm_media)) { | |
463 | case IFM_10_2: | 463 | case IFM_10_2: | |
464 | medname = "BNC"; | 464 | medname = "BNC"; | |
465 | break; | 465 | break; | |
466 | case IFM_10_5: | 466 | case IFM_10_5: | |
467 | medname = "AUI"; | 467 | medname = "AUI"; | |
468 | break; | 468 | break; | |
469 | case IFM_10_T: | 469 | case IFM_10_T: | |
470 | if (sc->sc_media.ifm_cur->ifm_media & IFM_FDX) | 470 | if (sc->sc_media.ifm_cur->ifm_media & IFM_FDX) | |
471 | medname = "UTP <full-duplex>"; | 471 | medname = "UTP <full-duplex>"; | |
472 | else | 472 | else | |
473 | medname = "UTP"; | 473 | medname = "UTP"; | |
474 | break; | 474 | break; | |
475 | default: | 475 | default: | |
476 | panic("cs_attach: impossible"); | 476 | panic("cs_attach: impossible"); | |
477 | } | 477 | } | |
478 | printf("%s: %s rev. %c, address %s, media %s\n", | 478 | printf("%s: %s rev. %c, address %s, media %s\n", | |
479 | device_xname(sc->sc_dev), | 479 | device_xname(sc->sc_dev), | |
480 | chipname, sc->sc_prodrev + 'A', ether_sprintf(sc->sc_enaddr), | 480 | chipname, sc->sc_prodrev + 'A', ether_sprintf(sc->sc_enaddr), | |
481 | medname); | 481 | medname); | |
482 | 482 | |||
483 | if (sc->sc_dma_attach) | 483 | if (sc->sc_dma_attach) | |
484 | (*sc->sc_dma_attach)(sc); | 484 | (*sc->sc_dma_attach)(sc); | |
485 | 485 | |||
486 | /* Attach the interface. */ | 486 | /* Attach the interface. */ | |
487 | if_attach(ifp); | 487 | if_attach(ifp); | |
488 | if_deferred_start_init(ifp, NULL); | 488 | if_deferred_start_init(ifp, NULL); | |
489 | ether_ifattach(ifp, sc->sc_enaddr); | 489 | ether_ifattach(ifp, sc->sc_enaddr); | |
490 | 490 | |||
491 | rnd_attach_source(&sc->rnd_source, device_xname(sc->sc_dev), | 491 | rnd_attach_source(&sc->rnd_source, device_xname(sc->sc_dev), | |
492 | RND_TYPE_NET, RND_FLAG_DEFAULT); | 492 | RND_TYPE_NET, RND_FLAG_DEFAULT); | |
493 | sc->sc_cfgflags |= CFGFLG_ATTACHED; | 493 | sc->sc_cfgflags |= CFGFLG_ATTACHED; | |
494 | 494 | |||
495 | if (pmf_device_register1(sc->sc_dev, NULL, NULL, cs_shutdown)) | 495 | if (pmf_device_register1(sc->sc_dev, NULL, NULL, cs_shutdown)) | |
496 | pmf_class_network_register(sc->sc_dev, ifp); | 496 | pmf_class_network_register(sc->sc_dev, ifp); | |
497 | else | 497 | else | |
498 | aprint_error_dev(sc->sc_dev, | 498 | aprint_error_dev(sc->sc_dev, | |
499 | "couldn't establish power handler\n"); | 499 | "couldn't establish power handler\n"); | |
500 | 500 | |||
501 | /* Reset the chip */ | 501 | /* Reset the chip */ | |
502 | if (cs_reset_chip(sc) == CS_ERROR) { | 502 | if (cs_reset_chip(sc) == CS_ERROR) { | |
503 | aprint_error_dev(sc->sc_dev, "reset failed\n"); | 503 | aprint_error_dev(sc->sc_dev, "reset failed\n"); | |
504 | cs_detach(sc); | 504 | cs_detach(sc); | |
505 | return 1; | 505 | return 1; | |
506 | } | 506 | } | |
507 | 507 | |||
508 | return 0; | 508 | return 0; | |
509 | } | 509 | } | |
510 | 510 | |||
511 | int | 511 | int | |
512 | cs_detach(struct cs_softc *sc) | 512 | cs_detach(struct cs_softc *sc) | |
513 | { | 513 | { | |
514 | struct ifnet *ifp = &sc->sc_ethercom.ec_if; | 514 | struct ifnet *ifp = &sc->sc_ethercom.ec_if; | |
515 | 515 | |||
516 | if (sc->sc_cfgflags & CFGFLG_ATTACHED) { | 516 | if (sc->sc_cfgflags & CFGFLG_ATTACHED) { | |
517 | rnd_detach_source(&sc->rnd_source); | 517 | rnd_detach_source(&sc->rnd_source); | |
518 | ether_ifdetach(ifp); | 518 | ether_ifdetach(ifp); | |
519 | if_detach(ifp); | 519 | if_detach(ifp); | |
520 | sc->sc_cfgflags &= ~CFGFLG_ATTACHED; | 520 | sc->sc_cfgflags &= ~CFGFLG_ATTACHED; | |
521 | } | 521 | } | |
522 | 522 | |||
523 | #if 0 | 523 | #if 0 | |
524 | /* XXX not necessary */ | 524 | /* XXX not necessary */ | |
525 | if (sc->sc_cfgflags & CFGFLG_DMA_MODE) { | 525 | if (sc->sc_cfgflags & CFGFLG_DMA_MODE) { | |
526 | isa_dmamem_unmap(sc->sc_ic, sc->sc_drq, sc->sc_dmabase, | 526 | isa_dmamem_unmap(sc->sc_ic, sc->sc_drq, sc->sc_dmabase, | |
527 | sc->sc_dmasize); | 527 | sc->sc_dmasize); | |
528 | isa_dmamem_free(sc->sc_ic, sc->sc_drq, sc->sc_dmaaddr, | 528 | isa_dmamem_free(sc->sc_ic, sc->sc_drq, sc->sc_dmaaddr, | |
529 | sc->sc_dmasize); | 529 | sc->sc_dmasize); | |
530 | isa_dmamap_destroy(sc->sc_ic, sc->sc_drq); | 530 | isa_dmamap_destroy(sc->sc_ic, sc->sc_drq); | |
531 | sc->sc_cfgflags &= ~CFGFLG_DMA_MODE; | 531 | sc->sc_cfgflags &= ~CFGFLG_DMA_MODE; | |
532 | } | 532 | } | |
533 | #endif | 533 | #endif | |
534 | 534 | |||
535 | pmf_device_deregister(sc->sc_dev); | 535 | pmf_device_deregister(sc->sc_dev); | |
536 | 536 | |||
537 | return 0; | 537 | return 0; | |
538 | } | 538 | } | |
539 | 539 | |||
540 | bool | 540 | bool | |
541 | cs_shutdown(device_t self, int howto) | 541 | cs_shutdown(device_t self, int howto) | |
542 | { | 542 | { | |
543 | struct cs_softc *sc; | 543 | struct cs_softc *sc; | |
544 | 544 | |||
545 | sc = device_private(self); | 545 | sc = device_private(self); | |
546 | cs_reset(sc); | 546 | cs_reset(sc); | |
547 | 547 | |||
548 | return true; | 548 | return true; | |
549 | } | 549 | } | |
550 | 550 | |||
551 | void | 551 | void | |
552 | cs_get_default_media(struct cs_softc *sc) | 552 | cs_get_default_media(struct cs_softc *sc) | |
553 | { | 553 | { | |
554 | uint16_t adp_cfg, xmit_ctl; | 554 | uint16_t adp_cfg, xmit_ctl; | |
555 | 555 | |||
556 | if (cs_verify_eeprom(sc) == CS_ERROR) { | 556 | if (cs_verify_eeprom(sc) == CS_ERROR) { | |
557 | aprint_error_dev(sc->sc_dev, | 557 | aprint_error_dev(sc->sc_dev, | |
558 | "cs_get_default_media: EEPROM missing or bad\n"); | 558 | "cs_get_default_media: EEPROM missing or bad\n"); | |
559 | goto fakeit; | 559 | goto fakeit; | |
560 | } | 560 | } | |
561 | 561 | |||
562 | if (cs_read_eeprom(sc, EEPROM_ADPTR_CFG, &adp_cfg) == CS_ERROR) { | 562 | if (cs_read_eeprom(sc, EEPROM_ADPTR_CFG, &adp_cfg) == CS_ERROR) { | |
563 | aprint_error_dev(sc->sc_dev, | 563 | aprint_error_dev(sc->sc_dev, | |
564 | "unable to read adapter config from EEPROM\n"); | 564 | "unable to read adapter config from EEPROM\n"); | |
565 | goto fakeit; | 565 | goto fakeit; | |
566 | } | 566 | } | |
567 | 567 | |||
568 | if (cs_read_eeprom(sc, EEPROM_XMIT_CTL, &xmit_ctl) == CS_ERROR) { | 568 | if (cs_read_eeprom(sc, EEPROM_XMIT_CTL, &xmit_ctl) == CS_ERROR) { | |
569 | aprint_error_dev(sc->sc_dev, | 569 | aprint_error_dev(sc->sc_dev, | |
570 | "unable to read transmit control from EEPROM\n"); | 570 | "unable to read transmit control from EEPROM\n"); | |
571 | goto fakeit; | 571 | goto fakeit; | |
572 | } | 572 | } | |
573 | 573 | |||
574 | switch (adp_cfg & ADPTR_CFG_MEDIA) { | 574 | switch (adp_cfg & ADPTR_CFG_MEDIA) { | |
575 | case ADPTR_CFG_AUI: | 575 | case ADPTR_CFG_AUI: | |
576 | ifmedia_set(&sc->sc_media, IFM_ETHER | IFM_10_5); | 576 | ifmedia_set(&sc->sc_media, IFM_ETHER | IFM_10_5); | |
577 | break; | 577 | break; | |
578 | case ADPTR_CFG_10BASE2: | 578 | case ADPTR_CFG_10BASE2: | |
579 | ifmedia_set(&sc->sc_media, IFM_ETHER | IFM_10_2); | 579 | ifmedia_set(&sc->sc_media, IFM_ETHER | IFM_10_2); | |
580 | break; | 580 | break; | |
581 | case ADPTR_CFG_10BASET: | 581 | case ADPTR_CFG_10BASET: | |
582 | default: | 582 | default: | |
583 | if (xmit_ctl & XMIT_CTL_FDX) | 583 | if (xmit_ctl & XMIT_CTL_FDX) | |
584 | ifmedia_set(&sc->sc_media, IFM_ETHER | IFM_10_T | 584 | ifmedia_set(&sc->sc_media, IFM_ETHER | IFM_10_T | |
585 | | IFM_FDX); | 585 | | IFM_FDX); | |
586 | else | 586 | else | |
587 | ifmedia_set(&sc->sc_media, IFM_ETHER | IFM_10_T); | 587 | ifmedia_set(&sc->sc_media, IFM_ETHER | IFM_10_T); | |
588 | break; | 588 | break; | |
589 | } | 589 | } | |
590 | return; | 590 | return; | |
591 | 591 | |||
592 | fakeit: | 592 | fakeit: | |
593 | aprint_error_dev(sc->sc_dev, | 593 | aprint_error_dev(sc->sc_dev, | |
594 | "WARNING: default media setting may be inaccurate\n"); | 594 | "WARNING: default media setting may be inaccurate\n"); | |
595 | /* XXX Arbitrary... */ | 595 | /* XXX Arbitrary... */ | |
596 | ifmedia_set(&sc->sc_media, IFM_ETHER | IFM_10_T); | 596 | ifmedia_set(&sc->sc_media, IFM_ETHER | IFM_10_T); | |
597 | } | 597 | } | |
598 | 598 | |||
599 | /* | 599 | /* | |
600 | * cs_scan_eeprom | 600 | * cs_scan_eeprom | |
601 | * | 601 | * | |
602 | * Attempt to take a complete copy of the eeprom into main memory. | 602 | * Attempt to take a complete copy of the eeprom into main memory. | |
603 | * this will allow faster parsing of the eeprom data. | 603 | * this will allow faster parsing of the eeprom data. | |
604 | * | 604 | * | |
605 | * Only tested against a 8920M's eeprom, but the data sheet for the | 605 | * Only tested against a 8920M's eeprom, but the data sheet for the | |
606 | * 8920A indicates that is uses the same layout. | 606 | * 8920A indicates that is uses the same layout. | |
607 | */ | 607 | */ | |
608 | int | 608 | int | |
609 | cs_scan_eeprom(struct cs_softc *sc) | 609 | cs_scan_eeprom(struct cs_softc *sc) | |
610 | { | 610 | { | |
611 | uint16_t result; | 611 | uint16_t result; | |
612 | int i; | 612 | int i; | |
613 | int eeprom_size; | 613 | int eeprom_size; | |
614 | uint8_t checksum = 0; | 614 | uint8_t checksum = 0; | |
615 | 615 | |||
616 | if (cs_verify_eeprom(sc) == CS_ERROR) { | 616 | if (cs_verify_eeprom(sc) == CS_ERROR) { | |
617 | aprint_error_dev(sc->sc_dev, | 617 | aprint_error_dev(sc->sc_dev, | |
618 | "cs_scan_params: EEPROM missing or bad\n"); | 618 | "cs_scan_params: EEPROM missing or bad\n"); | |
619 | return CS_ERROR; | 619 | return CS_ERROR; | |
620 | } | 620 | } | |
621 | 621 | |||
622 | /* | 622 | /* | |
623 | * Read the 0th word from the eeprom, it will tell us the length | 623 | * Read the 0th word from the eeprom, it will tell us the length | |
624 | * and if the eeprom is valid | 624 | * and if the eeprom is valid | |
625 | */ | 625 | */ | |
626 | cs_read_eeprom(sc, 0, &result); | 626 | cs_read_eeprom(sc, 0, &result); | |
627 | 627 | |||
628 | /* Check the eeprom signature */ | 628 | /* Check the eeprom signature */ | |
629 | if ((result & 0xE000) != 0xA000) { | 629 | if ((result & 0xE000) != 0xA000) { | |
630 | /* Empty eeprom */ | 630 | /* Empty eeprom */ | |
631 | return CS_ERROR; | 631 | return CS_ERROR; | |
632 | } | 632 | } | |
633 | 633 | |||
634 | /* | 634 | /* | |
635 | * Take the eeprom size (note the read value doesn't include the header | 635 | * Take the eeprom size (note the read value doesn't include the header | |
636 | * word) | 636 | * word) | |
637 | */ | 637 | */ | |
638 | eeprom_size = (result & 0xff) + 2; | 638 | eeprom_size = (result & 0xff) + 2; | |
639 | 639 | |||
640 | sc->eeprom_data = malloc(eeprom_size, M_DEVBUF, M_WAITOK); | 640 | sc->eeprom_data = malloc(eeprom_size, M_DEVBUF, M_WAITOK); | |
641 | if (sc->eeprom_data == NULL) { | 641 | if (sc->eeprom_data == NULL) { | |
642 | /* No memory, treat this as if there's no eeprom */ | 642 | /* No memory, treat this as if there's no eeprom */ | |
643 | return CS_ERROR; | 643 | return CS_ERROR; | |
644 | } | 644 | } | |
645 | 645 | |||
646 | sc->eeprom_size = eeprom_size; | 646 | sc->eeprom_size = eeprom_size; | |
647 | 647 | |||
648 | /* Read the eeprom into the buffer, also calculate the checksum */ | 648 | /* Read the eeprom into the buffer, also calculate the checksum */ | |
649 | for (i = 0; i < (eeprom_size >> 1); i++) { | 649 | for (i = 0; i < (eeprom_size >> 1); i++) { | |
650 | cs_read_eeprom(sc, i, &(sc->eeprom_data[i])); | 650 | cs_read_eeprom(sc, i, &(sc->eeprom_data[i])); | |
651 | checksum += (sc->eeprom_data[i] & 0xff00) >> 8; | 651 | checksum += (sc->eeprom_data[i] & 0xff00) >> 8; | |
652 | checksum += (sc->eeprom_data[i] & 0x00ff); | 652 | checksum += (sc->eeprom_data[i] & 0x00ff); | |
653 | } | 653 | } | |
654 | 654 | |||
655 | /* | 655 | /* | |
656 | * Validate checksum calculation, the sum of all the bytes should be 0, | 656 | * Validate checksum calculation, the sum of all the bytes should be 0, | |
657 | * as the high byte of the last word is the 2's complement of the | 657 | * as the high byte of the last word is the 2's complement of the | |
658 | * sum to that point. | 658 | * sum to that point. | |
659 | */ | 659 | */ | |
660 | if (checksum != 0) { | 660 | if (checksum != 0) { | |
661 | aprint_error_dev(sc->sc_dev, "eeprom checksum failure\n"); | 661 | aprint_error_dev(sc->sc_dev, "eeprom checksum failure\n"); | |
662 | return CS_ERROR; | 662 | return CS_ERROR; | |
663 | } | 663 | } | |
664 | 664 | |||
665 | return CS_OK; | 665 | return CS_OK; | |
666 | } | 666 | } | |
667 | 667 | |||
668 | static int | 668 | static int | |
669 | cs_read_pktpg_from_eeprom(struct cs_softc *sc, int pktpg, uint16_t *pValue) | 669 | cs_read_pktpg_from_eeprom(struct cs_softc *sc, int pktpg, uint16_t *pValue) | |
670 | { | 670 | { | |
671 | int x, maxword; | 671 | int x, maxword; | |
672 | 672 | |||
673 | /* Check that we have eeprom data */ | 673 | /* Check that we have eeprom data */ | |
674 | if ((sc->eeprom_data == NULL) || (sc->eeprom_size < 2)) | 674 | if ((sc->eeprom_data == NULL) || (sc->eeprom_size < 2)) | |
675 | return CS_ERROR; | 675 | return CS_ERROR; | |
676 | 676 | |||
677 | /* | 677 | /* | |
678 | * We only want to read the data words, the last word contains the | 678 | * We only want to read the data words, the last word contains the | |
679 | * checksum | 679 | * checksum | |
680 | */ | 680 | */ | |
681 | maxword = (sc->eeprom_size - 2) >> 1; | 681 | maxword = (sc->eeprom_size - 2) >> 1; | |
682 | 682 | |||
683 | /* Start 1 word in, as the first word is the length and signature */ | 683 | /* Start 1 word in, as the first word is the length and signature */ | |
684 | x = 1; | 684 | x = 1; | |
685 | 685 | |||
686 | while ( x < (maxword)) { | 686 | while ( x < (maxword)) { | |
687 | uint16_t header; | 687 | uint16_t header; | |
688 | int group_size; | 688 | int group_size; | |
689 | int offset; | 689 | int offset; | |
690 | int offset_max; | 690 | int offset_max; | |
691 | 691 | |||
692 | /* Read in the group header word */ | 692 | /* Read in the group header word */ | |
693 | header = sc->eeprom_data[x]; | 693 | header = sc->eeprom_data[x]; | |
694 | x++; /* Skip group header */ | 694 | x++; /* Skip group header */ | |
695 | 695 | |||
696 | /* | 696 | /* | |
697 | * Size of group in words is in the top 4 bits, note that it | 697 | * Size of group in words is in the top 4 bits, note that it | |
698 | * is one less than the number of words | 698 | * is one less than the number of words | |
699 | */ | 699 | */ | |
700 | group_size = header & 0xF000; | 700 | group_size = header & 0xF000; | |
701 | 701 | |||
702 | /* | 702 | /* | |
703 | * CS8900 Data sheet says this should be 0x01ff, | 703 | * CS8900 Data sheet says this should be 0x01ff, | |
704 | * but my cs8920 eeprom has higher offsets, | 704 | * but my cs8920 eeprom has higher offsets, | |
705 | * perhaps the 8920 allows higher offsets, otherwise | 705 | * perhaps the 8920 allows higher offsets, otherwise | |
706 | * it's writing to places that it shouldn't | 706 | * it's writing to places that it shouldn't | |
707 | */ | 707 | */ | |
708 | /* Work out the offsets this group covers */ | 708 | /* Work out the offsets this group covers */ | |
709 | offset = header & 0x0FFF; | 709 | offset = header & 0x0FFF; | |
710 | offset_max = offset + (group_size << 1); | 710 | offset_max = offset + (group_size << 1); | |
711 | 711 | |||
712 | /* Check if the pkgpg we're after is in this group */ | 712 | /* Check if the pkgpg we're after is in this group */ | |
713 | if ((offset <= pktpg) && (pktpg <= offset_max)) { | 713 | if ((offset <= pktpg) && (pktpg <= offset_max)) { | |
714 | /* The pkgpg value we want is in here */ | 714 | /* The pkgpg value we want is in here */ | |
715 | int eeprom_location; | 715 | int eeprom_location; | |
716 | 716 | |||
717 | eeprom_location = ((pktpg - offset) >> 1) ; | 717 | eeprom_location = ((pktpg - offset) >> 1) ; | |
718 | 718 | |||
719 | *pValue = sc->eeprom_data[x + eeprom_location]; | 719 | *pValue = sc->eeprom_data[x + eeprom_location]; | |
720 | return CS_OK; | 720 | return CS_OK; | |
721 | } else { | 721 | } else { | |
722 | /* Skip this group (+ 1 for first entry) */ | 722 | /* Skip this group (+ 1 for first entry) */ | |
723 | x += group_size + 1; | 723 | x += group_size + 1; | |
724 | } | 724 | } | |
725 | } | 725 | } | |
726 | 726 | |||
727 | /* | 727 | /* | |
728 | * If we've fallen out here then we don't have a value in the EEPROM | 728 | * If we've fallen out here then we don't have a value in the EEPROM | |
729 | * for this pktpg so return an error | 729 | * for this pktpg so return an error | |
730 | */ | 730 | */ | |
731 | return CS_ERROR; | 731 | return CS_ERROR; | |
732 | } | 732 | } | |
733 | 733 | |||
734 | int | 734 | int | |
735 | cs_get_params(struct cs_softc *sc) | 735 | cs_get_params(struct cs_softc *sc) | |
736 | { | 736 | { | |
737 | uint16_t isaConfig; | 737 | uint16_t isaConfig; | |
738 | uint16_t adapterConfig; | 738 | uint16_t adapterConfig; | |
739 | 739 | |||
740 | if (cs_verify_eeprom(sc) == CS_ERROR) { | 740 | if (cs_verify_eeprom(sc) == CS_ERROR) { | |
741 | aprint_error_dev(sc->sc_dev, | 741 | aprint_error_dev(sc->sc_dev, | |
742 | "cs_get_params: EEPROM missing or bad\n"); | 742 | "cs_get_params: EEPROM missing or bad\n"); | |
743 | return CS_ERROR; | 743 | return CS_ERROR; | |
744 | } | 744 | } | |
745 | 745 | |||
746 | if (sc->sc_cfgflags & CFGFLG_PARSE_EEPROM) { | 746 | if (sc->sc_cfgflags & CFGFLG_PARSE_EEPROM) { | |
747 | /* Get ISA configuration from the EEPROM */ | 747 | /* Get ISA configuration from the EEPROM */ | |
748 | if (cs_read_pktpg_from_eeprom(sc, PKTPG_BUS_CTL, &isaConfig) | 748 | if (cs_read_pktpg_from_eeprom(sc, PKTPG_BUS_CTL, &isaConfig) | |
749 | == CS_ERROR) { | 749 | == CS_ERROR) { | |
750 | /* | 750 | /* | |
751 | * Eeprom doesn't have this value, use data sheet | 751 | * Eeprom doesn't have this value, use data sheet | |
752 | * default | 752 | * default | |
753 | */ | 753 | */ | |
754 | isaConfig = 0x0017; | 754 | isaConfig = 0x0017; | |
755 | } | 755 | } | |
756 | 756 | |||
757 | /* Get adapter configuration from the EEPROM */ | 757 | /* Get adapter configuration from the EEPROM */ | |
758 | if (cs_read_pktpg_from_eeprom(sc, PKTPG_SELF_CTL, | 758 | if (cs_read_pktpg_from_eeprom(sc, PKTPG_SELF_CTL, | |
759 | &adapterConfig) == CS_ERROR) { | 759 | &adapterConfig) == CS_ERROR) { | |
760 | /* | 760 | /* | |
761 | * Eeprom doesn't have this value, use data sheet | 761 | * Eeprom doesn't have this value, use data sheet | |
762 | * default | 762 | * default | |
763 | */ | 763 | */ | |
764 | adapterConfig = 0x0015; | 764 | adapterConfig = 0x0015; | |
765 | } | 765 | } | |
766 | 766 | |||
767 | /* Copy the USE_SA flag */ | 767 | /* Copy the USE_SA flag */ | |
768 | if (isaConfig & BUS_CTL_USE_SA) | 768 | if (isaConfig & BUS_CTL_USE_SA) | |
769 | sc->sc_cfgflags |= CFGFLG_USE_SA; | 769 | sc->sc_cfgflags |= CFGFLG_USE_SA; | |
770 | 770 | |||
771 | /* Copy the IO Channel Ready flag */ | 771 | /* Copy the IO Channel Ready flag */ | |
772 | if (isaConfig & BUS_CTL_IOCHRDY) | 772 | if (isaConfig & BUS_CTL_IOCHRDY) | |
773 | sc->sc_cfgflags |= CFGFLG_IOCHRDY; | 773 | sc->sc_cfgflags |= CFGFLG_IOCHRDY; | |
774 | 774 | |||
775 | /* Copy the DC/DC Polarity flag */ | 775 | /* Copy the DC/DC Polarity flag */ | |
776 | if (adapterConfig & SELF_CTL_HCB1) | 776 | if (adapterConfig & SELF_CTL_HCB1) | |
777 | sc->sc_cfgflags |= CFGFLG_DCDC_POL; | 777 | sc->sc_cfgflags |= CFGFLG_DCDC_POL; | |
778 | } else { | 778 | } else { | |
779 | /* Get ISA configuration from the EEPROM */ | 779 | /* Get ISA configuration from the EEPROM */ | |
780 | if (cs_read_eeprom(sc, EEPROM_ISA_CFG, &isaConfig) == CS_ERROR) | 780 | if (cs_read_eeprom(sc, EEPROM_ISA_CFG, &isaConfig) == CS_ERROR) | |
781 | goto eeprom_bad; | 781 | goto eeprom_bad; | |
782 | 782 | |||
783 | /* Get adapter configuration from the EEPROM */ | 783 | /* Get adapter configuration from the EEPROM */ | |
784 | if (cs_read_eeprom(sc, EEPROM_ADPTR_CFG, &adapterConfig) | 784 | if (cs_read_eeprom(sc, EEPROM_ADPTR_CFG, &adapterConfig) | |
785 | == CS_ERROR) | 785 | == CS_ERROR) | |
786 | goto eeprom_bad; | 786 | goto eeprom_bad; | |
787 | 787 | |||
788 | /* Copy the USE_SA flag */ | 788 | /* Copy the USE_SA flag */ | |
789 | if (isaConfig & ISA_CFG_USE_SA) | 789 | if (isaConfig & ISA_CFG_USE_SA) | |
790 | sc->sc_cfgflags |= CFGFLG_USE_SA; | 790 | sc->sc_cfgflags |= CFGFLG_USE_SA; | |
791 | 791 | |||
792 | /* Copy the IO Channel Ready flag */ | 792 | /* Copy the IO Channel Ready flag */ | |
793 | if (isaConfig & ISA_CFG_IOCHRDY) | 793 | if (isaConfig & ISA_CFG_IOCHRDY) | |
794 | sc->sc_cfgflags |= CFGFLG_IOCHRDY; | 794 | sc->sc_cfgflags |= CFGFLG_IOCHRDY; | |
795 | 795 | |||
796 | /* Copy the DC/DC Polarity flag */ | 796 | /* Copy the DC/DC Polarity flag */ | |
797 | if (adapterConfig & ADPTR_CFG_DCDC_POL) | 797 | if (adapterConfig & ADPTR_CFG_DCDC_POL) | |
798 | sc->sc_cfgflags |= CFGFLG_DCDC_POL; | 798 | sc->sc_cfgflags |= CFGFLG_DCDC_POL; | |
799 | } | 799 | } | |
800 | 800 | |||
801 | return CS_OK; | 801 | return CS_OK; | |
802 | eeprom_bad: | 802 | eeprom_bad: | |
803 | aprint_error_dev(sc->sc_dev, | 803 | aprint_error_dev(sc->sc_dev, | |
804 | "cs_get_params: unable to read from EEPROM\n"); | 804 | "cs_get_params: unable to read from EEPROM\n"); | |
805 | return CS_ERROR; | 805 | return CS_ERROR; | |
806 | } | 806 | } | |
807 | 807 | |||
808 | int | 808 | int | |
809 | cs_get_enaddr(struct cs_softc *sc) | 809 | cs_get_enaddr(struct cs_softc *sc) | |
810 | { | 810 | { | |
811 | uint16_t myea[ETHER_ADDR_LEN / sizeof(uint16_t)]; | 811 | uint16_t myea[ETHER_ADDR_LEN / sizeof(uint16_t)]; | |
812 | int i; | 812 | int i; | |
813 | 813 | |||
814 | if (cs_verify_eeprom(sc) == CS_ERROR) { | 814 | if (cs_verify_eeprom(sc) == CS_ERROR) { | |
815 | aprint_error_dev(sc->sc_dev, | 815 | aprint_error_dev(sc->sc_dev, | |
816 | "cs_get_enaddr: EEPROM missing or bad\n"); | 816 | "cs_get_enaddr: EEPROM missing or bad\n"); | |
817 | return CS_ERROR; | 817 | return CS_ERROR; | |
818 | } | 818 | } | |
819 | 819 | |||
820 | /* Get Ethernet address from the EEPROM */ | 820 | /* Get Ethernet address from the EEPROM */ | |
821 | if (sc->sc_cfgflags & CFGFLG_PARSE_EEPROM) { | 821 | if (sc->sc_cfgflags & CFGFLG_PARSE_EEPROM) { | |
822 | if (cs_read_pktpg_from_eeprom(sc, PKTPG_IND_ADDR, &myea[0]) | 822 | if (cs_read_pktpg_from_eeprom(sc, PKTPG_IND_ADDR, &myea[0]) | |
823 | == CS_ERROR) | 823 | == CS_ERROR) | |
824 | goto eeprom_bad; | 824 | goto eeprom_bad; | |
825 | if (cs_read_pktpg_from_eeprom(sc, PKTPG_IND_ADDR + 2, &myea[1]) | 825 | if (cs_read_pktpg_from_eeprom(sc, PKTPG_IND_ADDR + 2, &myea[1]) | |
826 | == CS_ERROR) | 826 | == CS_ERROR) | |
827 | goto eeprom_bad; | 827 | goto eeprom_bad; | |
828 | if (cs_read_pktpg_from_eeprom(sc, PKTPG_IND_ADDR + 4, &myea[2]) | 828 | if (cs_read_pktpg_from_eeprom(sc, PKTPG_IND_ADDR + 4, &myea[2]) | |
829 | == CS_ERROR) | 829 | == CS_ERROR) | |
830 | goto eeprom_bad; | 830 | goto eeprom_bad; | |
831 | } else { | 831 | } else { | |
832 | if (cs_read_eeprom(sc, EEPROM_IND_ADDR_H, &myea[0]) == CS_ERROR) | 832 | if (cs_read_eeprom(sc, EEPROM_IND_ADDR_H, &myea[0]) == CS_ERROR) | |
833 | goto eeprom_bad; | 833 | goto eeprom_bad; | |
834 | if (cs_read_eeprom(sc, EEPROM_IND_ADDR_M, &myea[1]) == CS_ERROR) | 834 | if (cs_read_eeprom(sc, EEPROM_IND_ADDR_M, &myea[1]) == CS_ERROR) | |
835 | goto eeprom_bad; | 835 | goto eeprom_bad; | |
836 | if (cs_read_eeprom(sc, EEPROM_IND_ADDR_L, &myea[2]) == CS_ERROR) | 836 | if (cs_read_eeprom(sc, EEPROM_IND_ADDR_L, &myea[2]) == CS_ERROR) | |
837 | goto eeprom_bad; | 837 | goto eeprom_bad; | |
838 | } | 838 | } | |
839 | 839 | |||
840 | for (i = 0; i < __arraycount(myea); i++) { | 840 | for (i = 0; i < __arraycount(myea); i++) { | |
841 | sc->sc_enaddr[i * 2 + 0] = myea[i]; | 841 | sc->sc_enaddr[i * 2 + 0] = myea[i]; | |
842 | sc->sc_enaddr[i * 2 + 1] = myea[i] >> 8; | 842 | sc->sc_enaddr[i * 2 + 1] = myea[i] >> 8; | |
843 | } | 843 | } | |
844 | 844 | |||
845 | return CS_OK; | 845 | return CS_OK; | |
846 | 846 | |||
847 | eeprom_bad: | 847 | eeprom_bad: | |
848 | aprint_error_dev(sc->sc_dev, | 848 | aprint_error_dev(sc->sc_dev, | |
849 | "cs_get_enaddr: unable to read from EEPROM\n"); | 849 | "cs_get_enaddr: unable to read from EEPROM\n"); | |
850 | return CS_ERROR; | 850 | return CS_ERROR; | |
851 | } | 851 | } | |
852 | 852 | |||
853 | int | 853 | int | |
854 | cs_reset_chip(struct cs_softc *sc) | 854 | cs_reset_chip(struct cs_softc *sc) | |
855 | { | 855 | { | |
856 | int intState; | 856 | int intState; | |
857 | int x; | 857 | int x; | |
858 | 858 | |||
859 | /* Disable interrupts at the CPU so reset command is atomic */ | 859 | /* Disable interrupts at the CPU so reset command is atomic */ | |
860 | intState = splnet(); | 860 | intState = splnet(); | |
861 | 861 | |||
862 | /* | 862 | /* | |
863 | * We are now resetting the chip | 863 | * We are now resetting the chip | |
864 | * | 864 | * | |
865 | * A spurious interrupt is generated by the chip when it is reset. This | 865 | * A spurious interrupt is generated by the chip when it is reset. This | |
866 | * variable informs the interrupt handler to ignore this interrupt. | 866 | * variable informs the interrupt handler to ignore this interrupt. | |
867 | */ | 867 | */ | |
868 | sc->sc_resetting = TRUE; | 868 | sc->sc_resetting = TRUE; | |
869 | 869 | |||
870 | /* Issue a reset command to the chip */ | 870 | /* Issue a reset command to the chip */ | |
871 | CS_WRITE_PACKET_PAGE(sc, PKTPG_SELF_CTL, SELF_CTL_RESET); | 871 | CS_WRITE_PACKET_PAGE(sc, PKTPG_SELF_CTL, SELF_CTL_RESET); | |
872 | 872 | |||
873 | /* Re-enable interrupts at the CPU */ | 873 | /* Re-enable interrupts at the CPU */ | |
874 | splx(intState); | 874 | splx(intState); | |
875 | 875 | |||
876 | /* The chip is always in IO mode after a reset */ | 876 | /* The chip is always in IO mode after a reset */ | |
877 | sc->sc_memorymode = FALSE; | 877 | sc->sc_memorymode = FALSE; | |
878 | 878 | |||
879 | /* If transmission was in progress, it is not now */ | 879 | /* If transmission was in progress, it is not now */ | |
880 | sc->sc_txbusy = FALSE; | 880 | sc->sc_txbusy = FALSE; | |
881 | 881 | |||
882 | /* | 882 | /* | |
883 | * There was a delay(125); here, but it seems uneccesary 125 usec is | 883 | * There was a delay(125); here, but it seems uneccesary 125 usec is | |
884 | * 1/8000 of a second, not 1/8 of a second. the data sheet advises | 884 | * 1/8000 of a second, not 1/8 of a second. the data sheet advises | |
885 | * 1/10 of a second here, but the SI_BUSY and INIT_DONE loops below | 885 | * 1/10 of a second here, but the SI_BUSY and INIT_DONE loops below | |
886 | * should be sufficient. | 886 | * should be sufficient. | |
887 | */ | 887 | */ | |
888 | 888 | |||
889 | /* Transition SBHE to switch chip from 8-bit to 16-bit */ | 889 | /* Transition SBHE to switch chip from 8-bit to 16-bit */ | |
890 | IO_READ_1(sc, PORT_PKTPG_PTR + 0); | 890 | IO_READ_1(sc, PORT_PKTPG_PTR + 0); | |
891 | IO_READ_1(sc, PORT_PKTPG_PTR + 1); | 891 | IO_READ_1(sc, PORT_PKTPG_PTR + 1); | |
892 | IO_READ_1(sc, PORT_PKTPG_PTR + 0); | 892 | IO_READ_1(sc, PORT_PKTPG_PTR + 0); | |
893 | IO_READ_1(sc, PORT_PKTPG_PTR + 1); | 893 | IO_READ_1(sc, PORT_PKTPG_PTR + 1); | |
894 | 894 | |||
895 | /* Wait until the EEPROM is not busy */ | 895 | /* Wait until the EEPROM is not busy */ | |
896 | for (x = 0; x < MAXLOOP; x++) { | 896 | for (x = 0; x < MAXLOOP; x++) { | |
897 | if (!(CS_READ_PACKET_PAGE(sc, PKTPG_SELF_ST) & SELF_ST_SI_BUSY)) | 897 | if (!(CS_READ_PACKET_PAGE(sc, PKTPG_SELF_ST) & SELF_ST_SI_BUSY)) | |
898 | break; | 898 | break; | |
899 | } | 899 | } | |
900 | 900 | |||
901 | if (x == MAXLOOP) | 901 | if (x == MAXLOOP) | |
902 | return CS_ERROR; | 902 | return CS_ERROR; | |
903 | 903 | |||
904 | /* Wait until initialization is done */ | 904 | /* Wait until initialization is done */ | |
905 | for (x = 0; x < MAXLOOP; x++) { | 905 | for (x = 0; x < MAXLOOP; x++) { | |
906 | if (CS_READ_PACKET_PAGE(sc, PKTPG_SELF_ST) & SELF_ST_INIT_DONE) | 906 | if (CS_READ_PACKET_PAGE(sc, PKTPG_SELF_ST) & SELF_ST_INIT_DONE) | |
907 | break; | 907 | break; | |
908 | } | 908 | } | |
909 | 909 | |||
910 | if (x == MAXLOOP) | 910 | if (x == MAXLOOP) | |
911 | return CS_ERROR; | 911 | return CS_ERROR; | |
912 | 912 | |||
913 | /* Reset is no longer in progress */ | 913 | /* Reset is no longer in progress */ | |
914 | sc->sc_resetting = FALSE; | 914 | sc->sc_resetting = FALSE; | |
915 | 915 | |||
916 | return CS_OK; | 916 | return CS_OK; | |
917 | } | 917 | } | |
918 | 918 | |||
919 | int | 919 | int | |
920 | cs_verify_eeprom(struct cs_softc *sc) | 920 | cs_verify_eeprom(struct cs_softc *sc) | |
921 | { | 921 | { | |
922 | uint16_t self_status; | 922 | uint16_t self_status; | |
923 | 923 | |||
924 | /* Verify that the EEPROM is present and OK */ | 924 | /* Verify that the EEPROM is present and OK */ | |
925 | self_status = CS_READ_PACKET_PAGE_IO(sc, PKTPG_SELF_ST); | 925 | self_status = CS_READ_PACKET_PAGE_IO(sc, PKTPG_SELF_ST); | |
926 | if (((self_status & SELF_ST_EEP_PRES) && | 926 | if (((self_status & SELF_ST_EEP_PRES) && | |
927 | (self_status & SELF_ST_EEP_OK)) == 0) | 927 | (self_status & SELF_ST_EEP_OK)) == 0) | |
928 | return CS_ERROR; | 928 | return CS_ERROR; | |
929 | 929 | |||
930 | return CS_OK; | 930 | return CS_OK; | |
931 | } | 931 | } | |
932 | 932 | |||
933 | int | 933 | int | |
934 | cs_read_eeprom(struct cs_softc *sc, int offset, uint16_t *pValue) | 934 | cs_read_eeprom(struct cs_softc *sc, int offset, uint16_t *pValue) | |
935 | { | 935 | { | |
936 | int x; | 936 | int x; | |
937 | 937 | |||
938 | /* Ensure that the EEPROM is not busy */ | 938 | /* Ensure that the EEPROM is not busy */ | |
939 | for (x = 0; x < MAXLOOP; x++) { | 939 | for (x = 0; x < MAXLOOP; x++) { | |
940 | if (!(CS_READ_PACKET_PAGE_IO(sc, PKTPG_SELF_ST) & | 940 | if (!(CS_READ_PACKET_PAGE_IO(sc, PKTPG_SELF_ST) & | |
941 | SELF_ST_SI_BUSY)) | 941 | SELF_ST_SI_BUSY)) | |
942 | break; | 942 | break; | |
943 | } | 943 | } | |
944 | 944 | |||
945 | if (x == MAXLOOP) | 945 | if (x == MAXLOOP) | |
946 | return CS_ERROR; | 946 | return CS_ERROR; | |
947 | 947 | |||
948 | /* Issue the command to read the offset within the EEPROM */ | 948 | /* Issue the command to read the offset within the EEPROM */ | |
949 | CS_WRITE_PACKET_PAGE_IO(sc, PKTPG_EEPROM_CMD, | 949 | CS_WRITE_PACKET_PAGE_IO(sc, PKTPG_EEPROM_CMD, | |
950 | offset | EEPROM_CMD_READ); | 950 | offset | EEPROM_CMD_READ); | |
951 | 951 | |||
952 | /* Wait until the command is completed */ | 952 | /* Wait until the command is completed */ | |
953 | for (x = 0; x < MAXLOOP; x++) { | 953 | for (x = 0; x < MAXLOOP; x++) { | |
954 | if (!(CS_READ_PACKET_PAGE_IO(sc, PKTPG_SELF_ST) & | 954 | if (!(CS_READ_PACKET_PAGE_IO(sc, PKTPG_SELF_ST) & | |
955 | SELF_ST_SI_BUSY)) | 955 | SELF_ST_SI_BUSY)) | |
956 | break; | 956 | break; | |
957 | } | 957 | } | |
958 | 958 | |||
959 | if (x == MAXLOOP) | 959 | if (x == MAXLOOP) | |
960 | return CS_ERROR; | 960 | return CS_ERROR; | |
961 | 961 | |||
962 | /* Get the EEPROM data from the EEPROM Data register */ | 962 | /* Get the EEPROM data from the EEPROM Data register */ | |
963 | *pValue = CS_READ_PACKET_PAGE_IO(sc, PKTPG_EEPROM_DATA); | 963 | *pValue = CS_READ_PACKET_PAGE_IO(sc, PKTPG_EEPROM_DATA); | |
964 | 964 | |||
965 | return CS_OK; | 965 | return CS_OK; | |
966 | } | 966 | } | |
967 | 967 | |||
968 | void | 968 | void | |
969 | cs_initChip(struct cs_softc *sc) | 969 | cs_initChip(struct cs_softc *sc) | |
970 | { | 970 | { | |
971 | uint16_t busCtl; | 971 | uint16_t busCtl; | |
972 | uint16_t selfCtl; | 972 | uint16_t selfCtl; | |
973 | uint16_t v; | 973 | uint16_t v; | |
974 | uint16_t isaId; | 974 | uint16_t isaId; | |
975 | int i; | 975 | int i; | |
976 | int media = IFM_SUBTYPE(sc->sc_media.ifm_cur->ifm_media); | 976 | int media = IFM_SUBTYPE(sc->sc_media.ifm_cur->ifm_media); | |
977 | 977 | |||
978 | /* Disable reception and transmission of frames */ | 978 | /* Disable reception and transmission of frames */ | |
979 | CS_WRITE_PACKET_PAGE(sc, PKTPG_LINE_CTL, | 979 | CS_WRITE_PACKET_PAGE(sc, PKTPG_LINE_CTL, | |
980 | CS_READ_PACKET_PAGE(sc, PKTPG_LINE_CTL) & | 980 | CS_READ_PACKET_PAGE(sc, PKTPG_LINE_CTL) & | |
981 | ~LINE_CTL_RX_ON & ~LINE_CTL_TX_ON); | 981 | ~LINE_CTL_RX_ON & ~LINE_CTL_TX_ON); | |
982 | 982 | |||
983 | /* Disable interrupt at the chip */ | 983 | /* Disable interrupt at the chip */ | |
984 | CS_WRITE_PACKET_PAGE(sc, PKTPG_BUS_CTL, | 984 | CS_WRITE_PACKET_PAGE(sc, PKTPG_BUS_CTL, | |
985 | CS_READ_PACKET_PAGE(sc, PKTPG_BUS_CTL) & ~BUS_CTL_INT_ENBL); | 985 | CS_READ_PACKET_PAGE(sc, PKTPG_BUS_CTL) & ~BUS_CTL_INT_ENBL); | |
986 | 986 | |||
987 | /* If IOCHRDY is enabled then clear the bit in the busCtl register */ | 987 | /* If IOCHRDY is enabled then clear the bit in the busCtl register */ | |
988 | busCtl = CS_READ_PACKET_PAGE(sc, PKTPG_BUS_CTL); | 988 | busCtl = CS_READ_PACKET_PAGE(sc, PKTPG_BUS_CTL); | |
989 | if (sc->sc_cfgflags & CFGFLG_IOCHRDY) { | 989 | if (sc->sc_cfgflags & CFGFLG_IOCHRDY) { | |
990 | CS_WRITE_PACKET_PAGE(sc, PKTPG_BUS_CTL, | 990 | CS_WRITE_PACKET_PAGE(sc, PKTPG_BUS_CTL, | |
991 | busCtl & ~BUS_CTL_IOCHRDY); | 991 | busCtl & ~BUS_CTL_IOCHRDY); | |
992 | } else { | 992 | } else { | |
993 | CS_WRITE_PACKET_PAGE(sc, PKTPG_BUS_CTL, | 993 | CS_WRITE_PACKET_PAGE(sc, PKTPG_BUS_CTL, | |
994 | busCtl | BUS_CTL_IOCHRDY); | 994 | busCtl | BUS_CTL_IOCHRDY); | |
995 | } | 995 | } | |
996 | 996 | |||
997 | /* Set the Line Control register to match the media type */ | 997 | /* Set the Line Control register to match the media type */ | |
998 | if (media == IFM_10_T) | 998 | if (media == IFM_10_T) | |
999 | CS_WRITE_PACKET_PAGE(sc, PKTPG_LINE_CTL, LINE_CTL_10BASET); | 999 | CS_WRITE_PACKET_PAGE(sc, PKTPG_LINE_CTL, LINE_CTL_10BASET); | |
1000 | else | 1000 | else | |
1001 | CS_WRITE_PACKET_PAGE(sc, PKTPG_LINE_CTL, LINE_CTL_AUI_ONLY); | 1001 | CS_WRITE_PACKET_PAGE(sc, PKTPG_LINE_CTL, LINE_CTL_AUI_ONLY); | |
1002 | 1002 | |||
1003 | /* | 1003 | /* | |
1004 | * Set the BSTATUS/HC1 pin to be used as HC1. HC1 is used to | 1004 | * Set the BSTATUS/HC1 pin to be used as HC1. HC1 is used to | |
1005 | * enable the DC/DC converter | 1005 | * enable the DC/DC converter | |
1006 | */ | 1006 | */ | |
1007 | selfCtl = SELF_CTL_HC1E; | 1007 | selfCtl = SELF_CTL_HC1E; | |
1008 | 1008 | |||
1009 | /* If the media type is 10Base2 */ | 1009 | /* If the media type is 10Base2 */ | |
1010 | if (media == IFM_10_2) { | 1010 | if (media == IFM_10_2) { | |
1011 | /* Enable the DC/DC converter if it has a low enable. */ | 1011 | /* Enable the DC/DC converter if it has a low enable. */ | |
1012 | if ((sc->sc_cfgflags & CFGFLG_DCDC_POL) == 0) | 1012 | if ((sc->sc_cfgflags & CFGFLG_DCDC_POL) == 0) | |
1013 | /* | 1013 | /* | |
1014 | * Set the HCB1 bit, which causes the HC1 pin to go | 1014 | * Set the HCB1 bit, which causes the HC1 pin to go | |
1015 | * low. | 1015 | * low. | |
1016 | */ | 1016 | */ | |
1017 | selfCtl |= SELF_CTL_HCB1; | 1017 | selfCtl |= SELF_CTL_HCB1; | |
1018 | } else { /* Media type is 10BaseT or AUI */ | 1018 | } else { /* Media type is 10BaseT or AUI */ | |
1019 | /* Disable the DC/DC converter if it has a high enable. */ | 1019 | /* Disable the DC/DC converter if it has a high enable. */ | |
1020 | if ((sc->sc_cfgflags & CFGFLG_DCDC_POL) != 0) { | 1020 | if ((sc->sc_cfgflags & CFGFLG_DCDC_POL) != 0) { | |
1021 | /* | 1021 | /* | |
1022 | * Set the HCB1 bit, which causes the HC1 pin to go | 1022 | * Set the HCB1 bit, which causes the HC1 pin to go | |
1023 | * low. | 1023 | * low. | |
1024 | */ | 1024 | */ | |
1025 | selfCtl |= SELF_CTL_HCB1; | 1025 | selfCtl |= SELF_CTL_HCB1; | |
1026 | } | 1026 | } | |
1027 | } | 1027 | } | |
1028 | CS_WRITE_PACKET_PAGE(sc, PKTPG_SELF_CTL, selfCtl); | 1028 | CS_WRITE_PACKET_PAGE(sc, PKTPG_SELF_CTL, selfCtl); | |
1029 | 1029 | |||
1030 | /* Enable normal link pulse */ | 1030 | /* Enable normal link pulse */ | |
1031 | if (sc->sc_prodid == PROD_ID_CS8920 || sc->sc_prodid == PROD_ID_CS8920M) | 1031 | if (sc->sc_prodid == PROD_ID_CS8920 || sc->sc_prodid == PROD_ID_CS8920M) | |
1032 | CS_WRITE_PACKET_PAGE(sc, PKTPG_AUTONEG_CTL, AUTOCTL_NLP_ENABLE); | 1032 | CS_WRITE_PACKET_PAGE(sc, PKTPG_AUTONEG_CTL, AUTOCTL_NLP_ENABLE); | |
1033 | 1033 | |||
1034 | /* Enable full-duplex, if appropriate */ | 1034 | /* Enable full-duplex, if appropriate */ | |
1035 | if (sc->sc_media.ifm_cur->ifm_media & IFM_FDX) | 1035 | if (sc->sc_media.ifm_cur->ifm_media & IFM_FDX) | |
1036 | CS_WRITE_PACKET_PAGE(sc, PKTPG_TEST_CTL, TEST_CTL_FDX); | 1036 | CS_WRITE_PACKET_PAGE(sc, PKTPG_TEST_CTL, TEST_CTL_FDX); | |
1037 | 1037 | |||
1038 | /* RX_CTL set in cs_set_ladr_filt(), below */ | 1038 | /* RX_CTL set in cs_set_ladr_filt(), below */ | |
1039 | 1039 | |||
1040 | /* Enable all transmission interrupts */ | 1040 | /* Enable all transmission interrupts */ | |
1041 | CS_WRITE_PACKET_PAGE(sc, PKTPG_TX_CFG, TX_CFG_ALL_IE); | 1041 | CS_WRITE_PACKET_PAGE(sc, PKTPG_TX_CFG, TX_CFG_ALL_IE); | |
1042 | 1042 | |||
1043 | /* Accept all receive interrupts */ | 1043 | /* Accept all receive interrupts */ | |
1044 | CS_WRITE_PACKET_PAGE(sc, PKTPG_RX_CFG, RX_CFG_ALL_IE); | 1044 | CS_WRITE_PACKET_PAGE(sc, PKTPG_RX_CFG, RX_CFG_ALL_IE); | |
1045 | 1045 | |||
1046 | /* | 1046 | /* | |
1047 | * Configure Operational Modes | 1047 | * Configure Operational Modes | |
1048 | * | 1048 | * | |
1049 | * I have turned off the BUF_CFG_RX_MISS_IE, to speed things up, this | 1049 | * I have turned off the BUF_CFG_RX_MISS_IE, to speed things up, this | |
1050 | * is a better way to do it because the card has a counter which can be | 1050 | * is a better way to do it because the card has a counter which can be | |
1051 | * read to update the RX_MISS counter. This saves many interrupts. | 1051 | * read to update the RX_MISS counter. This saves many interrupts. | |
1052 | * | 1052 | * | |
1053 | * I have turned on the tx and rx overflow interrupts to counter using | 1053 | * I have turned on the tx and rx overflow interrupts to counter using | |
1054 | * the receive miss interrupt. This is a better estimate of errors | 1054 | * the receive miss interrupt. This is a better estimate of errors | |
1055 | * and requires lower system overhead. | 1055 | * and requires lower system overhead. | |
1056 | */ | 1056 | */ | |
1057 | CS_WRITE_PACKET_PAGE(sc, PKTPG_BUF_CFG, BUF_CFG_TX_UNDR_IE | | 1057 | CS_WRITE_PACKET_PAGE(sc, PKTPG_BUF_CFG, BUF_CFG_TX_UNDR_IE | | |
1058 | BUF_CFG_RX_DMA_IE); | 1058 | BUF_CFG_RX_DMA_IE); | |
1059 | 1059 | |||
1060 | if (sc->sc_dma_chipinit) | 1060 | if (sc->sc_dma_chipinit) | |
1061 | (*sc->sc_dma_chipinit)(sc); | 1061 | (*sc->sc_dma_chipinit)(sc); | |
1062 | 1062 | |||
1063 | /* If memory mode is enabled */ | 1063 | /* If memory mode is enabled */ | |
1064 | if (sc->sc_cfgflags & CFGFLG_MEM_MODE) { | 1064 | if (sc->sc_cfgflags & CFGFLG_MEM_MODE) { | |
1065 | /* If external logic is present for address decoding */ | 1065 | /* If external logic is present for address decoding */ | |
1066 | if (CS_READ_PACKET_PAGE(sc, PKTPG_SELF_ST) & SELF_ST_EL_PRES) { | 1066 | if (CS_READ_PACKET_PAGE(sc, PKTPG_SELF_ST) & SELF_ST_EL_PRES) { | |
1067 | /* | 1067 | /* | |
1068 | * Program the external logic to decode address bits | 1068 | * Program the external logic to decode address bits | |
1069 | * SA20-SA23 | 1069 | * SA20-SA23 | |
1070 | */ | 1070 | */ | |
1071 | CS_WRITE_PACKET_PAGE(sc, PKTPG_EEPROM_CMD, | 1071 | CS_WRITE_PACKET_PAGE(sc, PKTPG_EEPROM_CMD, | |
1072 | ((sc->sc_pktpgaddr & 0xffffff) >> 20) | | 1072 | ((sc->sc_pktpgaddr & 0xffffff) >> 20) | | |
1073 | EEPROM_CMD_ELSEL); | 1073 | EEPROM_CMD_ELSEL); | |
1074 | } | 1074 | } | |
1075 | 1075 | |||
1076 | /* | 1076 | /* | |
1077 | * Write the packet page base physical address to the memory | 1077 | * Write the packet page base physical address to the memory | |
1078 | * base register. | 1078 | * base register. | |
1079 | */ | 1079 | */ | |
1080 | CS_WRITE_PACKET_PAGE(sc, PKTPG_MEM_BASE + 0, | 1080 | CS_WRITE_PACKET_PAGE(sc, PKTPG_MEM_BASE + 0, | |
1081 | sc->sc_pktpgaddr & 0xFFFF); | 1081 | sc->sc_pktpgaddr & 0xFFFF); | |
1082 | CS_WRITE_PACKET_PAGE(sc, PKTPG_MEM_BASE + 2, | 1082 | CS_WRITE_PACKET_PAGE(sc, PKTPG_MEM_BASE + 2, | |
1083 | sc->sc_pktpgaddr >> 16); | 1083 | sc->sc_pktpgaddr >> 16); | |
1084 | busCtl = BUS_CTL_MEM_MODE; | 1084 | busCtl = BUS_CTL_MEM_MODE; | |
1085 | 1085 | |||
1086 | /* Tell the chip to read the addresses off the SA pins */ | 1086 | /* Tell the chip to read the addresses off the SA pins */ | |
1087 | if (sc->sc_cfgflags & CFGFLG_USE_SA) { | 1087 | if (sc->sc_cfgflags & CFGFLG_USE_SA) { | |
1088 | busCtl |= BUS_CTL_USE_SA; | 1088 | busCtl |= BUS_CTL_USE_SA; | |
1089 | } | 1089 | } | |
1090 | CS_WRITE_PACKET_PAGE(sc, PKTPG_BUS_CTL, | 1090 | CS_WRITE_PACKET_PAGE(sc, PKTPG_BUS_CTL, | |
1091 | CS_READ_PACKET_PAGE(sc, PKTPG_BUS_CTL) | busCtl); | 1091 | CS_READ_PACKET_PAGE(sc, PKTPG_BUS_CTL) | busCtl); | |
1092 | 1092 | |||
1093 | /* We are in memory mode now! */ | 1093 | /* We are in memory mode now! */ | |
1094 | sc->sc_memorymode = TRUE; | 1094 | sc->sc_memorymode = TRUE; | |
1095 | 1095 | |||
1096 | /* | 1096 | /* | |
1097 | * Wait here (10ms) for the chip to swap over. this is the | 1097 | * Wait here (10ms) for the chip to swap over. this is the | |
1098 | * maximum time that this could take. | 1098 | * maximum time that this could take. | |
1099 | */ | 1099 | */ | |
1100 | delay(10000); | 1100 | delay(10000); | |
1101 | 1101 | |||
1102 | /* Verify that we can read from the chip */ | 1102 | /* Verify that we can read from the chip */ | |
1103 | isaId = CS_READ_PACKET_PAGE(sc, PKTPG_EISA_NUM); | 1103 | isaId = CS_READ_PACKET_PAGE(sc, PKTPG_EISA_NUM); | |
1104 | 1104 | |||
1105 | /* | 1105 | /* | |
1106 | * As a last minute sanity check before actually using mapped | 1106 | * As a last minute sanity check before actually using mapped | |
1107 | * memory we verify that we can read the isa number from the | 1107 | * memory we verify that we can read the isa number from the | |
1108 | * chip in memory mode. | 1108 | * chip in memory mode. | |
1109 | */ | 1109 | */ | |
1110 | if (isaId != EISA_NUM_CRYSTAL) { | 1110 | if (isaId != EISA_NUM_CRYSTAL) { | |
1111 | aprint_error_dev(sc->sc_dev, | 1111 | aprint_error_dev(sc->sc_dev, | |
1112 | "failed to enable memory mode\n"); | 1112 | "failed to enable memory mode\n"); | |
1113 | sc->sc_memorymode = FALSE; | 1113 | sc->sc_memorymode = FALSE; | |
1114 | } else { | 1114 | } else { | |
1115 | /* | 1115 | /* | |
1116 | * We are in memory mode so if we aren't using DMA, | 1116 | * We are in memory mode so if we aren't using DMA, | |
1117 | * then program the chip to interrupt early. | 1117 | * then program the chip to interrupt early. | |
1118 | */ | 1118 | */ | |
1119 | if ((sc->sc_cfgflags & CFGFLG_DMA_MODE) == 0) { | 1119 | if ((sc->sc_cfgflags & CFGFLG_DMA_MODE) == 0) { | |
1120 | CS_WRITE_PACKET_PAGE(sc, PKTPG_BUF_CFG, | 1120 | CS_WRITE_PACKET_PAGE(sc, PKTPG_BUF_CFG, | |
1121 | BUF_CFG_RX_DEST_IE | | 1121 | BUF_CFG_RX_DEST_IE | | |
1122 | BUF_CFG_RX_MISS_OVER_IE | | 1122 | BUF_CFG_RX_MISS_OVER_IE | | |
1123 | BUF_CFG_TX_COL_OVER_IE); | 1123 | BUF_CFG_TX_COL_OVER_IE); | |
1124 | } | 1124 | } | |
1125 | } | 1125 | } | |
1126 | 1126 | |||
1127 | } | 1127 | } | |
1128 | 1128 | |||
1129 | /* Put Ethernet address into the Individual Address register */ | 1129 | /* Put Ethernet address into the Individual Address register */ | |
1130 | for (i = 0; i < 6; i += 2) { | 1130 | for (i = 0; i < 6; i += 2) { | |
1131 | v = sc->sc_enaddr[i + 0] | (sc->sc_enaddr[i + 1]) << 8; | 1131 | v = sc->sc_enaddr[i + 0] | (sc->sc_enaddr[i + 1]) << 8; | |
1132 | CS_WRITE_PACKET_PAGE(sc, PKTPG_IND_ADDR + i, v); | 1132 | CS_WRITE_PACKET_PAGE(sc, PKTPG_IND_ADDR + i, v); | |
1133 | } | 1133 | } | |
1134 | 1134 | |||
1135 | if (sc->sc_irq != -1) { | 1135 | if (sc->sc_irq != -1) { | |
1136 | /* Set the interrupt level in the chip */ | 1136 | /* Set the interrupt level in the chip */ | |
1137 | if (sc->sc_prodid == PROD_ID_CS8900) { | 1137 | if (sc->sc_prodid == PROD_ID_CS8900) { | |
1138 | if (sc->sc_irq == 5) | 1138 | if (sc->sc_irq == 5) | |
1139 | CS_WRITE_PACKET_PAGE(sc, PKTPG_INT_NUM, 3); | 1139 | CS_WRITE_PACKET_PAGE(sc, PKTPG_INT_NUM, 3); | |
1140 | else | 1140 | else | |
1141 | CS_WRITE_PACKET_PAGE(sc, PKTPG_INT_NUM, | 1141 | CS_WRITE_PACKET_PAGE(sc, PKTPG_INT_NUM, | |
1142 | (sc->sc_irq) - 10); | 1142 | (sc->sc_irq) - 10); | |
1143 | } else { /* CS8920 */ | 1143 | } else { /* CS8920 */ | |
1144 | CS_WRITE_PACKET_PAGE(sc, PKTPG_8920_INT_NUM, | 1144 | CS_WRITE_PACKET_PAGE(sc, PKTPG_8920_INT_NUM, | |
1145 | sc->sc_irq); | 1145 | sc->sc_irq); | |
1146 | } | 1146 | } | |
1147 | } | 1147 | } | |
1148 | 1148 | |||
1149 | /* Write the multicast mask to the address filter register */ | 1149 | /* Write the multicast mask to the address filter register */ | |
1150 | cs_set_ladr_filt(sc, &sc->sc_ethercom); | 1150 | cs_set_ladr_filt(sc, &sc->sc_ethercom); | |
1151 | 1151 | |||
1152 | /* Enable reception and transmission of frames */ | 1152 | /* Enable reception and transmission of frames */ | |
1153 | CS_WRITE_PACKET_PAGE(sc, PKTPG_LINE_CTL, | 1153 | CS_WRITE_PACKET_PAGE(sc, PKTPG_LINE_CTL, | |
1154 | CS_READ_PACKET_PAGE(sc, PKTPG_LINE_CTL) | | 1154 | CS_READ_PACKET_PAGE(sc, PKTPG_LINE_CTL) | | |
1155 | LINE_CTL_RX_ON | LINE_CTL_TX_ON); | 1155 | LINE_CTL_RX_ON | LINE_CTL_TX_ON); | |
1156 | 1156 | |||
1157 | /* Enable interrupt at the chip */ | 1157 | /* Enable interrupt at the chip */ | |
1158 | CS_WRITE_PACKET_PAGE(sc, PKTPG_BUS_CTL, | 1158 | CS_WRITE_PACKET_PAGE(sc, PKTPG_BUS_CTL, | |
1159 | CS_READ_PACKET_PAGE(sc, PKTPG_BUS_CTL) | BUS_CTL_INT_ENBL); | 1159 | CS_READ_PACKET_PAGE(sc, PKTPG_BUS_CTL) | BUS_CTL_INT_ENBL); | |
1160 | } | 1160 | } | |
1161 | 1161 | |||
1162 | int | 1162 | int | |
1163 | cs_init(struct ifnet *ifp) | 1163 | cs_init(struct ifnet *ifp) | |
1164 | { | 1164 | { | |
1165 | int intState; | 1165 | int intState; | |
1166 | int error = CS_OK; | 1166 | int error = CS_OK; | |
1167 | struct cs_softc *sc = ifp->if_softc; | 1167 | struct cs_softc *sc = ifp->if_softc; | |
1168 | 1168 | |||
1169 | if (cs_enable(sc)) | 1169 | if (cs_enable(sc)) | |
1170 | goto out; | 1170 | goto out; | |
1171 | 1171 | |||
1172 | cs_stop(ifp, 0); | 1172 | cs_stop(ifp, 0); | |
1173 | 1173 | |||
1174 | intState = splnet(); | 1174 | intState = splnet(); | |
1175 | 1175 | |||
1176 | #if 0 | 1176 | #if 0 | |
1177 | /* Mark the interface as down */ | 1177 | /* Mark the interface as down */ | |
1178 | sc->sc_ethercom.ec_if.if_flags &= ~(IFF_UP | IFF_RUNNING); | 1178 | sc->sc_ethercom.ec_if.if_flags &= ~(IFF_UP | IFF_RUNNING); | |
1179 | #endif | 1179 | #endif | |
1180 | 1180 | |||
1181 | #ifdef CS_DEBUG | 1181 | #ifdef CS_DEBUG | |
1182 | /* Enable debugging */ | 1182 | /* Enable debugging */ | |
1183 | sc->sc_ethercom.ec_if.if_flags |= IFF_DEBUG; | 1183 | sc->sc_ethercom.ec_if.if_flags |= IFF_DEBUG; | |
1184 | #endif | 1184 | #endif | |
1185 | 1185 | |||
1186 | /* Reset the chip */ | 1186 | /* Reset the chip */ | |
1187 | if ((error = cs_reset_chip(sc)) == CS_OK) { | 1187 | if ((error = cs_reset_chip(sc)) == CS_OK) { | |
1188 | /* Initialize the chip */ | 1188 | /* Initialize the chip */ | |
1189 | cs_initChip(sc); | 1189 | cs_initChip(sc); | |
1190 | 1190 | |||
1191 | /* Mark the interface as running */ | 1191 | /* Mark the interface as running */ | |
1192 | sc->sc_ethercom.ec_if.if_flags |= IFF_RUNNING; | 1192 | sc->sc_ethercom.ec_if.if_flags |= IFF_RUNNING; | |
1193 | sc->sc_ethercom.ec_if.if_flags &= ~IFF_OACTIVE; | 1193 | sc->sc_ethercom.ec_if.if_flags &= ~IFF_OACTIVE; | |
1194 | sc->sc_ethercom.ec_if.if_timer = 0; | 1194 | sc->sc_ethercom.ec_if.if_timer = 0; | |
1195 | 1195 | |||
1196 | /* Assume we have carrier until we are told otherwise. */ | 1196 | /* Assume we have carrier until we are told otherwise. */ | |
1197 | sc->sc_carrier = 1; | 1197 | sc->sc_carrier = 1; | |
1198 | } else | 1198 | } else | |
1199 | aprint_error_dev(sc->sc_dev, "unable to reset chip\n"); | 1199 | aprint_error_dev(sc->sc_dev, "unable to reset chip\n"); | |
1200 | 1200 | |||
1201 | splx(intState); | 1201 | splx(intState); | |
1202 | out: | 1202 | out: | |
1203 | if (error == CS_OK) | 1203 | if (error == CS_OK) | |
1204 | return 0; | 1204 | return 0; | |
1205 | return EIO; | 1205 | return EIO; | |
1206 | } | 1206 | } | |
1207 | 1207 | |||
1208 | void | 1208 | void | |
1209 | cs_set_ladr_filt(struct cs_softc *sc, struct ethercom *ec) | 1209 | cs_set_ladr_filt(struct cs_softc *sc, struct ethercom *ec) | |
1210 | { | 1210 | { | |
1211 | struct ifnet *ifp = &ec->ec_if; | 1211 | struct ifnet *ifp = &ec->ec_if; | |
1212 | struct ether_multi *enm; | 1212 | struct ether_multi *enm; | |
1213 | struct ether_multistep step; | 1213 | struct ether_multistep step; | |
1214 | uint16_t af[4]; | 1214 | uint16_t af[4]; | |
1215 | uint16_t port, mask, index; | 1215 | uint16_t port, mask, index; | |
1216 | 1216 | |||
1217 | /* | 1217 | /* | |
1218 | * Set up multicast address filter by passing all multicast addresses | 1218 | * Set up multicast address filter by passing all multicast addresses | |
1219 | * through a crc generator, and then using the high order 6 bits as an | 1219 | * through a crc generator, and then using the high order 6 bits as an | |
1220 | * index into the 64 bit logical address filter. The high order bit | 1220 | * index into the 64 bit logical address filter. The high order bit | |
1221 | * selects the word, while the rest of the bits select the bit within | 1221 | * selects the word, while the rest of the bits select the bit within | |
1222 | * the word. | 1222 | * the word. | |
1223 | */ | 1223 | */ | |
1224 | if (ifp->if_flags & IFF_PROMISC) { | 1224 | if (ifp->if_flags & IFF_PROMISC) { | |
1225 | /* Accept all valid frames. */ | 1225 | /* Accept all valid frames. */ | |
1226 | CS_WRITE_PACKET_PAGE(sc, PKTPG_RX_CTL, | 1226 | CS_WRITE_PACKET_PAGE(sc, PKTPG_RX_CTL, | |
1227 | RX_CTL_PROMISC_A | RX_CTL_RX_OK_A | | 1227 | RX_CTL_PROMISC_A | RX_CTL_RX_OK_A | | |
1228 | RX_CTL_IND_A | RX_CTL_BCAST_A | RX_CTL_MCAST_A); | 1228 | RX_CTL_IND_A | RX_CTL_BCAST_A | RX_CTL_MCAST_A); | |
1229 | ifp->if_flags |= IFF_ALLMULTI; | 1229 | ifp->if_flags |= IFF_ALLMULTI; | |
1230 | return; | 1230 | return; | |
1231 | } | 1231 | } | |
1232 | 1232 | |||
1233 | /* | 1233 | /* | |
1234 | * Accept frames if a. crc valid, b. individual address match c. | 1234 | * Accept frames if a. crc valid, b. individual address match c. | |
1235 | * broadcast address,and d. multicast addresses matched in the hash | 1235 | * broadcast address,and d. multicast addresses matched in the hash | |
1236 | * filter | 1236 | * filter | |
1237 | */ | 1237 | */ | |
1238 | CS_WRITE_PACKET_PAGE(sc, PKTPG_RX_CTL, | 1238 | CS_WRITE_PACKET_PAGE(sc, PKTPG_RX_CTL, | |
1239 | RX_CTL_RX_OK_A | RX_CTL_IND_A | RX_CTL_BCAST_A | RX_CTL_MCAST_A); | 1239 | RX_CTL_RX_OK_A | RX_CTL_IND_A | RX_CTL_BCAST_A | RX_CTL_MCAST_A); | |
1240 | 1240 | |||
1241 | 1241 | |||
1242 | /* | 1242 | /* | |
1243 | * Start off with all multicast flag clear, set it if we need to | 1243 | * Start off with all multicast flag clear, set it if we need to | |
1244 | * later, otherwise we will leave it. | 1244 | * later, otherwise we will leave it. | |
1245 | */ | 1245 | */ | |
1246 | ifp->if_flags &= ~IFF_ALLMULTI; | 1246 | ifp->if_flags &= ~IFF_ALLMULTI; | |
1247 | af[0] = af[1] = af[2] = af[3] = 0x0000; | 1247 | af[0] = af[1] = af[2] = af[3] = 0x0000; | |
1248 | 1248 | |||
1249 | /* | 1249 | /* | |
1250 | * Loop through all the multicast addresses unless we get a range of | 1250 | * Loop through all the multicast addresses unless we get a range of | |
1251 | * addresses, in which case we will just accept all packets. | 1251 | * addresses, in which case we will just accept all packets. | |
1252 | * Justification for this is given in the next comment. | 1252 | * Justification for this is given in the next comment. | |
1253 | */ | 1253 | */ | |
1254 | ETHER_LOCK(ec); | 1254 | ETHER_LOCK(ec); | |
1255 | ETHER_FIRST_MULTI(step, ec, enm); | 1255 | ETHER_FIRST_MULTI(step, ec, enm); | |
1256 | while (enm != NULL) { | 1256 | while (enm != NULL) { | |
1257 | if (memcmp(enm->enm_addrlo, enm->enm_addrhi, | 1257 | if (memcmp(enm->enm_addrlo, enm->enm_addrhi, | |
1258 | sizeof enm->enm_addrlo)) { | 1258 | sizeof enm->enm_addrlo)) { | |
1259 | /* | 1259 | /* | |
1260 | * We must listen to a range of multicast addresses. | 1260 | * We must listen to a range of multicast addresses. | |
1261 | * For now, just accept all multicasts, rather than | 1261 | * For now, just accept all multicasts, rather than | |
1262 | * trying to set only those filter bits needed to match | 1262 | * trying to set only those filter bits needed to match | |
1263 | * the range. (At this time, the only use of address | 1263 | * the range. (At this time, the only use of address | |
1264 | * ranges is for IP multicast routing, for which the | 1264 | * ranges is for IP multicast routing, for which the | |
1265 | * range is big enough to require all bits set.) | 1265 | * range is big enough to require all bits set.) | |
1266 | */ | 1266 | */ | |
1267 | ifp->if_flags |= IFF_ALLMULTI; | 1267 | ifp->if_flags |= IFF_ALLMULTI; | |
1268 | af[0] = af[1] = af[2] = af[3] = 0xffff; | 1268 | af[0] = af[1] = af[2] = af[3] = 0xffff; | |
1269 | break; | 1269 | break; | |
1270 | } else { | 1270 | } else { | |
1271 | /* | 1271 | /* | |
1272 | * We have got an individual address so just set that | 1272 | * We have got an individual address so just set that | |
1273 | * bit. | 1273 | * bit. | |
1274 | */ | 1274 | */ | |
1275 | index = cs_hash_index(enm->enm_addrlo); | 1275 | index = cs_hash_index(enm->enm_addrlo); | |
1276 | 1276 | |||
1277 | /* Set the bit the Logical address filter. */ | 1277 | /* Set the bit the Logical address filter. */ | |
1278 | port = (uint16_t) (index >> 4); | 1278 | port = (uint16_t) (index >> 4); | |
1279 | mask = (uint16_t) (1 << (index & 0xf)); | 1279 | mask = (uint16_t) (1 << (index & 0xf)); | |
1280 | af[port] |= mask; | 1280 | af[port] |= mask; | |
1281 | 1281 | |||
1282 | ETHER_NEXT_MULTI(step, enm); | 1282 | ETHER_NEXT_MULTI(step, enm); | |
1283 | } | 1283 | } | |
1284 | } | 1284 | } | |
1285 | ETHER_UNLOCK(ec); | 1285 | ETHER_UNLOCK(ec); | |
1286 | 1286 | |||
1287 | /* Now program the chip with the addresses */ | 1287 | /* Now program the chip with the addresses */ | |
1288 | CS_WRITE_PACKET_PAGE(sc, PKTPG_LOG_ADDR + 0, af[0]); | 1288 | CS_WRITE_PACKET_PAGE(sc, PKTPG_LOG_ADDR + 0, af[0]); | |
1289 | CS_WRITE_PACKET_PAGE(sc, PKTPG_LOG_ADDR + 2, af[1]); | 1289 | CS_WRITE_PACKET_PAGE(sc, PKTPG_LOG_ADDR + 2, af[1]); | |
1290 | CS_WRITE_PACKET_PAGE(sc, PKTPG_LOG_ADDR + 4, af[2]); | 1290 | CS_WRITE_PACKET_PAGE(sc, PKTPG_LOG_ADDR + 4, af[2]); | |
1291 | CS_WRITE_PACKET_PAGE(sc, PKTPG_LOG_ADDR + 6, af[3]); | 1291 | CS_WRITE_PACKET_PAGE(sc, PKTPG_LOG_ADDR + 6, af[3]); | |
1292 | return; | 1292 | return; | |
1293 | } | 1293 | } | |
1294 | 1294 | |||
1295 | uint16_t | 1295 | uint16_t | |
1296 | cs_hash_index(char *addr) | 1296 | cs_hash_index(char *addr) | |
1297 | { | 1297 | { | |
1298 | uint32_t crc; | 1298 | uint32_t crc; | |
1299 | uint16_t hash_code; | 1299 | uint16_t hash_code; | |
1300 | 1300 | |||
1301 | crc = ether_crc32_le(addr, ETHER_ADDR_LEN); | 1301 | crc = ether_crc32_le(addr, ETHER_ADDR_LEN); | |
1302 | 1302 | |||
1303 | hash_code = crc >> 26; | 1303 | hash_code = crc >> 26; | |
1304 | return hash_code; | 1304 | return hash_code; | |
1305 | } | 1305 | } | |
1306 | 1306 | |||
1307 | void | 1307 | void | |
1308 | cs_reset(struct cs_softc *sc) | 1308 | cs_reset(struct cs_softc *sc) | |
1309 | { | 1309 | { | |
1310 | 1310 | |||
1311 | /* Mark the interface as down */ | 1311 | /* Mark the interface as down */ | |
1312 | sc->sc_ethercom.ec_if.if_flags &= ~IFF_RUNNING; | 1312 | sc->sc_ethercom.ec_if.if_flags &= ~IFF_RUNNING; | |
1313 | 1313 | |||
1314 | /* Reset the chip */ | 1314 | /* Reset the chip */ | |
1315 | cs_reset_chip(sc); | 1315 | cs_reset_chip(sc); | |
1316 | } | 1316 | } | |
1317 | 1317 | |||
1318 | int | 1318 | int | |
1319 | cs_ioctl(struct ifnet *ifp, u_long cmd, void *data) | 1319 | cs_ioctl(struct ifnet *ifp, u_long cmd, void *data) | |
1320 | { | 1320 | { | |
1321 | struct cs_softc *sc = ifp->if_softc; | 1321 | struct cs_softc *sc = ifp->if_softc; | |
1322 | int state; | 1322 | int state; | |
1323 | int result; | 1323 | int result; | |
1324 | 1324 | |||
1325 | state = splnet(); | 1325 | state = splnet(); | |
1326 | 1326 | |||
1327 | result = 0; /* Only set if something goes wrong */ | 1327 | result = 0; /* Only set if something goes wrong */ | |
1328 | 1328 | |||
1329 | switch (cmd) { | 1329 | switch (cmd) { | |
1330 | default: | 1330 | default: | |
1331 | result = ether_ioctl(ifp, cmd, data); | 1331 | result = ether_ioctl(ifp, cmd, data); | |
1332 | if (result == ENETRESET) { | 1332 | if (result == ENETRESET) { | |
1333 | if (ifp->if_flags & IFF_RUNNING) { | 1333 | if (ifp->if_flags & IFF_RUNNING) { | |
1334 | /* | 1334 | /* | |
1335 | * Multicast list has changed. Set the | 1335 | * Multicast list has changed. Set the | |
1336 | * hardware filter accordingly. | 1336 | * hardware filter accordingly. | |
1337 | */ | 1337 | */ | |
1338 | cs_set_ladr_filt(sc, &sc->sc_ethercom); | 1338 | cs_set_ladr_filt(sc, &sc->sc_ethercom); | |
1339 | } | 1339 | } | |
1340 | result = 0; | 1340 | result = 0; | |
1341 | } | 1341 | } | |
1342 | break; | 1342 | break; | |
1343 | } | 1343 | } | |
1344 | 1344 | |||
1345 | splx(state); | 1345 | splx(state); | |
1346 | 1346 | |||
1347 | return result; | 1347 | return result; | |
1348 | } | 1348 | } | |
1349 | 1349 | |||
1350 | int | 1350 | int | |
1351 | cs_mediachange(struct ifnet *ifp) | 1351 | cs_mediachange(struct ifnet *ifp) | |
1352 | { | 1352 | { | |
1353 | 1353 | |||
1354 | /* | 1354 | /* | |
1355 | * Current media is already set up. Just reset the interface | 1355 | * Current media is already set up. Just reset the interface | |
1356 | * to let the new value take hold. | 1356 | * to let the new value take hold. | |
1357 | */ | 1357 | */ | |
1358 | cs_init(ifp); | 1358 | cs_init(ifp); | |
1359 | return 0; | 1359 | return 0; | |
1360 | } | 1360 | } | |
1361 | 1361 | |||
1362 | void | 1362 | void | |
1363 | cs_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr) | 1363 | cs_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr) | |
1364 | { | 1364 | { | |
1365 | struct cs_softc *sc = ifp->if_softc; | 1365 | struct cs_softc *sc = ifp->if_softc; | |
1366 | 1366 | |||
1367 | /* The currently selected media is always the active media. */ | 1367 | /* The currently selected media is always the active media. */ | |
1368 | ifmr->ifm_active = sc->sc_media.ifm_cur->ifm_media; | 1368 | ifmr->ifm_active = sc->sc_media.ifm_cur->ifm_media; | |
1369 | 1369 | |||
1370 | if (ifp->if_flags & IFF_UP) { | 1370 | if (ifp->if_flags & IFF_UP) { | |
1371 | /* Interface up, status is valid. */ | 1371 | /* Interface up, status is valid. */ | |
1372 | ifmr->ifm_status = IFM_AVALID | | 1372 | ifmr->ifm_status = IFM_AVALID | | |
1373 | (sc->sc_carrier ? IFM_ACTIVE : 0); | 1373 | (sc->sc_carrier ? IFM_ACTIVE : 0); | |
1374 | } | 1374 | } | |
1375 | else ifmr->ifm_status = 0; | 1375 | else ifmr->ifm_status = 0; | |
1376 | } | 1376 | } | |
1377 | 1377 | |||
1378 | int | 1378 | int | |
1379 | cs_intr(void *arg) | 1379 | cs_intr(void *arg) | |
1380 | { | 1380 | { | |
1381 | struct cs_softc *sc = arg; | 1381 | struct cs_softc *sc = arg; | |
1382 | uint16_t Event; | 1382 | uint16_t Event; | |
1383 | uint16_t rndEvent; | 1383 | uint16_t rndEvent; | |
1384 | 1384 | |||
1385 | /*printf("cs_intr %p\n", sc);*/ | 1385 | /*printf("cs_intr %p\n", sc);*/ | |
1386 | /* Ignore any interrupts that happen while the chip is being reset */ | 1386 | /* Ignore any interrupts that happen while the chip is being reset */ | |
1387 | if (sc->sc_resetting) { | 1387 | if (sc->sc_resetting) { | |
1388 | printf("%s: cs_intr: reset in progress\n", | 1388 | printf("%s: cs_intr: reset in progress\n", | |
1389 | device_xname(sc->sc_dev)); | 1389 | device_xname(sc->sc_dev)); | |
1390 | return 1; | 1390 | return 1; | |
1391 | } | 1391 | } | |
1392 | 1392 | |||
1393 | /* Read an event from the Interrupt Status Queue */ | 1393 | /* Read an event from the Interrupt Status Queue */ | |
1394 | if (sc->sc_memorymode) | 1394 | if (sc->sc_memorymode) | |
1395 | Event = CS_READ_PACKET_PAGE(sc, PKTPG_ISQ); | 1395 | Event = CS_READ_PACKET_PAGE(sc, PKTPG_ISQ); | |
1396 | else | 1396 | else | |
1397 | Event = CS_READ_PORT(sc, PORT_ISQ); | 1397 | Event = CS_READ_PORT(sc, PORT_ISQ); | |
1398 | 1398 | |||
1399 | if ((Event & REG_NUM_MASK) == 0 || Event == 0xffff) | 1399 | if ((Event & REG_NUM_MASK) == 0 || Event == 0xffff) | |
1400 | return 0; /* Not ours */ | 1400 | return 0; /* Not ours */ | |
1401 | 1401 | |||
1402 | rndEvent = Event; | 1402 | rndEvent = Event; | |
1403 | 1403 | |||
1404 | /* Process all the events in the Interrupt Status Queue */ | 1404 | /* Process all the events in the Interrupt Status Queue */ | |
1405 | while ((Event & REG_NUM_MASK) != 0 && Event != 0xffff) { | 1405 | while ((Event & REG_NUM_MASK) != 0 && Event != 0xffff) { | |
1406 | /* Dispatch to an event handler based on the register number */ | 1406 | /* Dispatch to an event handler based on the register number */ | |
1407 | switch (Event & REG_NUM_MASK) { | 1407 | switch (Event & REG_NUM_MASK) { | |
1408 | case REG_NUM_RX_EVENT: | 1408 | case REG_NUM_RX_EVENT: | |
1409 | cs_receive_event(sc, Event); | 1409 | cs_receive_event(sc, Event); | |
1410 | break; | 1410 | break; | |
1411 | case REG_NUM_TX_EVENT: | 1411 | case REG_NUM_TX_EVENT: | |
1412 | cs_transmit_event(sc, Event); | 1412 | cs_transmit_event(sc, Event); | |
1413 | break; | 1413 | break; | |
1414 | case REG_NUM_BUF_EVENT: | 1414 | case REG_NUM_BUF_EVENT: | |
1415 | cs_buffer_event(sc, Event); | 1415 | cs_buffer_event(sc, Event); | |
1416 | break; | 1416 | break; | |
1417 | case REG_NUM_TX_COL: | 1417 | case REG_NUM_TX_COL: | |
1418 | case REG_NUM_RX_MISS: | 1418 | case REG_NUM_RX_MISS: | |
1419 | cs_counter_event(sc, Event); | 1419 | cs_counter_event(sc, Event); | |
1420 | break; | 1420 | break; | |
1421 | default: | 1421 | default: | |
1422 | printf("%s: unknown interrupt event 0x%x\n", | 1422 | printf("%s: unknown interrupt event 0x%x\n", | |
1423 | device_xname(sc->sc_dev), Event); | 1423 | device_xname(sc->sc_dev), Event); | |
1424 | break; | 1424 | break; | |
1425 | } | 1425 | } | |
1426 | 1426 | |||
1427 | /* Read another event from the Interrupt Status Queue */ | 1427 | /* Read another event from the Interrupt Status Queue */ | |
1428 | if (sc->sc_memorymode) | 1428 | if (sc->sc_memorymode) | |
1429 | Event = CS_READ_PACKET_PAGE(sc, PKTPG_ISQ); | 1429 | Event = CS_READ_PACKET_PAGE(sc, PKTPG_ISQ); | |
1430 | else | 1430 | else | |
1431 | Event = CS_READ_PORT(sc, PORT_ISQ); | 1431 | Event = CS_READ_PORT(sc, PORT_ISQ); | |
1432 | } | 1432 | } | |
1433 | 1433 | |||
1434 | /* have handled the interrupt */ | 1434 | /* have handled the interrupt */ | |
1435 | rnd_add_uint32(&sc->rnd_source, rndEvent); | 1435 | rnd_add_uint32(&sc->rnd_source, rndEvent); | |
1436 | return 1; | 1436 | return 1; | |
1437 | } | 1437 | } | |
1438 | 1438 | |||
1439 | void | 1439 | void | |
1440 | cs_counter_event(struct cs_softc *sc, uint16_t cntEvent) | 1440 | cs_counter_event(struct cs_softc *sc, uint16_t cntEvent) | |
1441 | { | 1441 | { | |
1442 | struct ifnet *ifp; | 1442 | struct ifnet *ifp; | |
1443 | uint16_t errorCount; | 1443 | uint16_t errorCount; | |
1444 | 1444 | |||
1445 | ifp = &sc->sc_ethercom.ec_if; | 1445 | ifp = &sc->sc_ethercom.ec_if; | |
1446 | 1446 | |||
1447 | switch (cntEvent & REG_NUM_MASK) { | 1447 | switch (cntEvent & REG_NUM_MASK) { | |
1448 | case REG_NUM_TX_COL: | 1448 | case REG_NUM_TX_COL: | |
1449 | /* The count should be read before an overflow occurs. */ | 1449 | /* The count should be read before an overflow occurs. */ | |
1450 | errorCount = CS_READ_PACKET_PAGE(sc, PKTPG_TX_COL); | 1450 | errorCount = CS_READ_PACKET_PAGE(sc, PKTPG_TX_COL); | |
1451 | /* | 1451 | /* | |
1452 | * The tramsit event routine always checks the number of | 1452 | * The tramsit event routine always checks the number of | |
1453 | * collisions for any packet so we don't increment any | 1453 | * collisions for any packet so we don't increment any | |
1454 | * counters here, as they should already have been | 1454 | * counters here, as they should already have been | |
1455 | * considered. | 1455 | * considered. | |
1456 | */ | 1456 | */ | |
1457 | break; | 1457 | break; | |
1458 | case REG_NUM_RX_MISS: | 1458 | case REG_NUM_RX_MISS: | |
1459 | /* The count should be read before an overflow occurs. */ | 1459 | /* The count should be read before an overflow occurs. */ | |
1460 | errorCount = CS_READ_PACKET_PAGE(sc, PKTPG_RX_MISS); | 1460 | errorCount = CS_READ_PACKET_PAGE(sc, PKTPG_RX_MISS); | |
1461 | /* | 1461 | /* | |
1462 | * Increment the input error count, the first 6bits are the | 1462 | * Increment the input error count, the first 6bits are the | |
1463 | * register id. | 1463 | * register id. | |
1464 | */ | 1464 | */ | |
1465 | ifp->if_ierrors += ((errorCount & 0xffC0) >> 6); | 1465 | if_statadd(ifp, if_ierrors, (errorCount & 0xffC0) >> 6); | |
1466 | break; | 1466 | break; | |
1467 | default: | 1467 | default: | |
1468 | /* Do nothing */ | 1468 | /* Do nothing */ | |
1469 | break; | 1469 | break; | |
1470 | } | 1470 | } | |
1471 | } | 1471 | } | |
1472 | 1472 | |||
1473 | void | 1473 | void | |
1474 | cs_buffer_event(struct cs_softc *sc, uint16_t bufEvent) | 1474 | cs_buffer_event(struct cs_softc *sc, uint16_t bufEvent) | |
1475 | { | 1475 | { | |
1476 | 1476 | |||
1477 | /* | 1477 | /* | |
1478 | * Multiple events can be in the buffer event register at one time so | 1478 | * Multiple events can be in the buffer event register at one time so | |
1479 | * a standard switch statement will not suffice, here every event | 1479 | * a standard switch statement will not suffice, here every event | |
1480 | * must be checked. | 1480 | * must be checked. | |
1481 | */ | 1481 | */ | |
1482 | 1482 | |||
1483 | /* | 1483 | /* | |
1484 | * If 128 bits have been rxed by the time we get here, the dest event | 1484 | * If 128 bits have been rxed by the time we get here, the dest event | |
1485 | * will be cleared and 128 event will be set. | 1485 | * will be cleared and 128 event will be set. | |
1486 | */ | 1486 | */ | |
1487 | if ((bufEvent & (BUF_EVENT_RX_DEST | BUF_EVENT_RX_128)) != 0) | 1487 | if ((bufEvent & (BUF_EVENT_RX_DEST | BUF_EVENT_RX_128)) != 0) | |
1488 | cs_process_rx_early(sc); | 1488 | cs_process_rx_early(sc); | |
1489 | 1489 | |||
1490 | if (bufEvent & BUF_EVENT_RX_DMA) { | 1490 | if (bufEvent & BUF_EVENT_RX_DMA) { | |
1491 | /* Process the receive data */ | 1491 | /* Process the receive data */ | |
1492 | if (sc->sc_dma_process_rx) | 1492 | if (sc->sc_dma_process_rx) | |
1493 | (*sc->sc_dma_process_rx)(sc); | 1493 | (*sc->sc_dma_process_rx)(sc); | |
1494 | else | 1494 | else | |
1495 | /* Should panic? */ | 1495 | /* Should panic? */ | |
1496 | aprint_error_dev(sc->sc_dev, "unexpected DMA event\n"); | 1496 | aprint_error_dev(sc->sc_dev, "unexpected DMA event\n"); | |
1497 | } | 1497 | } | |
1498 | 1498 | |||
1499 | if (bufEvent & BUF_EVENT_TX_UNDR) { | 1499 | if (bufEvent & BUF_EVENT_TX_UNDR) { | |
1500 | #if 0 | 1500 | #if 0 | |
1501 | /* | 1501 | /* | |
1502 | * This can happen occasionally, and it's not worth worrying | 1502 | * This can happen occasionally, and it's not worth worrying | |
1503 | * about. | 1503 | * about. | |
1504 | */ | 1504 | */ | |
1505 | printf("%s: transmit underrun (%d -> %d)\n", | 1505 | printf("%s: transmit underrun (%d -> %d)\n", | |
1506 | device_xname(sc->sc_dev), sc->sc_xe_ent, | 1506 | device_xname(sc->sc_dev), sc->sc_xe_ent, | |
1507 | cs_xmit_early_table[sc->sc_xe_ent].worse); | 1507 | cs_xmit_early_table[sc->sc_xe_ent].worse); | |
1508 | #endif | 1508 | #endif | |
1509 | sc->sc_xe_ent = cs_xmit_early_table[sc->sc_xe_ent].worse; | 1509 | sc->sc_xe_ent = cs_xmit_early_table[sc->sc_xe_ent].worse; | |
1510 | sc->sc_xe_togo = | 1510 | sc->sc_xe_togo = | |
1511 | cs_xmit_early_table[sc->sc_xe_ent].better_count; | 1511 | cs_xmit_early_table[sc->sc_xe_ent].better_count; | |
1512 | 1512 | |||
1513 | /* had an underrun, transmit is finished */ | 1513 | /* had an underrun, transmit is finished */ | |
1514 | sc->sc_txbusy = FALSE; | 1514 | sc->sc_txbusy = FALSE; | |
1515 | } | 1515 | } | |
1516 | 1516 | |||
1517 | if (bufEvent & BUF_EVENT_SW_INT) | 1517 | if (bufEvent & BUF_EVENT_SW_INT) | |
1518 | printf("%s: software initiated interrupt\n", | 1518 | printf("%s: software initiated interrupt\n", | |
1519 | device_xname(sc->sc_dev)); | 1519 | device_xname(sc->sc_dev)); | |
1520 | } | 1520 | } | |
1521 | 1521 | |||
1522 | void | 1522 | void | |
1523 | cs_transmit_event(struct cs_softc *sc, uint16_t txEvent) | 1523 | cs_transmit_event(struct cs_softc *sc, uint16_t txEvent) | |
1524 | { | 1524 | { | |
1525 | struct ifnet *ifp = &sc->sc_ethercom.ec_if; | 1525 | struct ifnet *ifp = &sc->sc_ethercom.ec_if; | |
1526 | 1526 | |||
1527 | /* If there were any errors transmitting this frame */ | 1527 | /* If there were any errors transmitting this frame */ | |
1528 | if (txEvent & (TX_EVENT_LOSS_CRS | TX_EVENT_SQE_ERR | | 1528 | if (txEvent & (TX_EVENT_LOSS_CRS | TX_EVENT_SQE_ERR | | |
1529 | TX_EVENT_OUT_WIN | TX_EVENT_JABBER | TX_EVENT_16_COLL)) { | 1529 | TX_EVENT_OUT_WIN | TX_EVENT_JABBER | TX_EVENT_16_COLL)) { | |
1530 | /* Increment the output error count */ | 1530 | /* Increment the output error count */ | |
1531 | ifp->if_oerrors++; | 1531 | if_statinc(ifp, if_oerrors); | |
1532 | 1532 | |||
1533 | /* Note carrier loss. */ | 1533 | /* Note carrier loss. */ | |
1534 | if (txEvent & TX_EVENT_LOSS_CRS) | 1534 | if (txEvent & TX_EVENT_LOSS_CRS) | |
1535 | sc->sc_carrier = 0; | 1535 | sc->sc_carrier = 0; | |
1536 | 1536 | |||
1537 | /* If debugging is enabled then log error messages */ | 1537 | /* If debugging is enabled then log error messages */ | |
1538 | if (ifp->if_flags & IFF_DEBUG) { | 1538 | if (ifp->if_flags & IFF_DEBUG) { | |
1539 | if (txEvent & TX_EVENT_LOSS_CRS) | 1539 | if (txEvent & TX_EVENT_LOSS_CRS) | |
1540 | aprint_error_dev(sc->sc_dev, "lost carrier\n"); | 1540 | aprint_error_dev(sc->sc_dev, "lost carrier\n"); | |
1541 | 1541 | |||
1542 | if (txEvent & TX_EVENT_SQE_ERR) | 1542 | if (txEvent & TX_EVENT_SQE_ERR) | |
1543 | aprint_error_dev(sc->sc_dev, "SQE error\n"); | 1543 | aprint_error_dev(sc->sc_dev, "SQE error\n"); | |
1544 | 1544 | |||
1545 | if (txEvent & TX_EVENT_OUT_WIN) | 1545 | if (txEvent & TX_EVENT_OUT_WIN) | |
1546 | aprint_error_dev(sc->sc_dev, | 1546 | aprint_error_dev(sc->sc_dev, | |
1547 | "out-of-window collision\n"); | 1547 | "out-of-window collision\n"); | |
1548 | 1548 | |||
1549 | if (txEvent & TX_EVENT_JABBER) | 1549 | if (txEvent & TX_EVENT_JABBER) | |
1550 | aprint_error_dev(sc->sc_dev, "jabber\n"); | 1550 | aprint_error_dev(sc->sc_dev, "jabber\n"); | |
1551 | 1551 | |||
1552 | if (txEvent & TX_EVENT_16_COLL) | 1552 | if (txEvent & TX_EVENT_16_COLL) | |
1553 | aprint_error_dev(sc->sc_dev, | 1553 | aprint_error_dev(sc->sc_dev, | |
1554 | "16 collisions\n"); | 1554 | "16 collisions\n"); | |
1555 | } | 1555 | } | |
1556 | } else { | 1556 | } else { | |
1557 | /* Transmission successful, carrier is up. */ | 1557 | /* Transmission successful, carrier is up. */ | |
1558 | sc->sc_carrier = 1; | 1558 | sc->sc_carrier = 1; | |
1559 | #ifdef SHARK | 1559 | #ifdef SHARK | |
1560 | ledNetActive(); | 1560 | ledNetActive(); | |
1561 | #endif | 1561 | #endif | |
1562 | } | 1562 | } | |
1563 | 1563 | |||
1564 | /* Add the number of collisions for this frame */ | 1564 | /* Add the number of collisions for this frame */ | |
1565 | net_stat_ref_t nsr = IF_STAT_GETREF(ifp); | |||
1565 | if (txEvent & TX_EVENT_16_COLL) | 1566 | if (txEvent & TX_EVENT_16_COLL) | |
1566 | ifp->if_collisions += 16; | 1567 | if_statadd_ref(nsr, if_collisions, 16); | |
1567 | else | 1568 | else | |
1568 | ifp->if_collisions += ((txEvent & TX_EVENT_COLL_MASK) >> 11); | 1569 | if_statadd_ref(nsr, if_collisions, | |
1570 | ((txEvent & TX_EVENT_COLL_MASK) >> 11)); | |||
1569 | 1571 | |||
1570 | ifp->if_opackets++; | 1572 | if_statinc_ref(nsr, if_opackets); | |
1573 | IF_STAT_PUTREF(ifp); | |||
1571 | 1574 | |||
1572 | /* Transmission is no longer in progress */ | 1575 | /* Transmission is no longer in progress */ | |
1573 | sc->sc_txbusy = FALSE; | 1576 | sc->sc_txbusy = FALSE; | |
1574 | 1577 | |||
1575 | /* If there is more to transmit, start the next transmission */ | 1578 | /* If there is more to transmit, start the next transmission */ | |
1576 | if_schedule_deferred_start(ifp); | 1579 | if_schedule_deferred_start(ifp); | |
1577 | } | 1580 | } | |
1578 | 1581 | |||
1579 | void | 1582 | void | |
1580 | cs_print_rx_errors(struct cs_softc *sc, uint16_t rxEvent) | 1583 | cs_print_rx_errors(struct cs_softc *sc, uint16_t rxEvent) | |
1581 | { | 1584 | { | |
1582 | 1585 | |||
1583 | if (rxEvent & RX_EVENT_RUNT) | 1586 | if (rxEvent & RX_EVENT_RUNT) | |
1584 | aprint_error_dev(sc->sc_dev, "runt\n"); | 1587 | aprint_error_dev(sc->sc_dev, "runt\n"); | |
1585 | 1588 | |||
1586 | if (rxEvent & RX_EVENT_X_DATA) | 1589 | if (rxEvent & RX_EVENT_X_DATA) | |
1587 | aprint_error_dev(sc->sc_dev, "extra data\n"); | 1590 | aprint_error_dev(sc->sc_dev, "extra data\n"); | |
1588 | 1591 | |||
1589 | if (rxEvent & RX_EVENT_CRC_ERR) { | 1592 | if (rxEvent & RX_EVENT_CRC_ERR) { | |
1590 | if (rxEvent & RX_EVENT_DRIBBLE) | 1593 | if (rxEvent & RX_EVENT_DRIBBLE) | |
1591 | aprint_error_dev(sc->sc_dev, "alignment error\n"); | 1594 | aprint_error_dev(sc->sc_dev, "alignment error\n"); | |
1592 | else | 1595 | else | |
1593 | aprint_error_dev(sc->sc_dev, "CRC error\n"); | 1596 | aprint_error_dev(sc->sc_dev, "CRC error\n"); | |
1594 | } else { | 1597 | } else { | |
1595 | if (rxEvent & RX_EVENT_DRIBBLE) | 1598 | if (rxEvent & RX_EVENT_DRIBBLE) | |
1596 | aprint_error_dev(sc->sc_dev, "dribble bits\n"); | 1599 | aprint_error_dev(sc->sc_dev, "dribble bits\n"); | |
1597 | } | 1600 | } | |
1598 | } | 1601 | } | |
1599 | 1602 | |||
1600 | void | 1603 | void | |
1601 | cs_receive_event(struct cs_softc *sc, uint16_t rxEvent) | 1604 | cs_receive_event(struct cs_softc *sc, uint16_t rxEvent) | |
1602 | { | 1605 | { | |
1603 | struct ifnet *ifp = &sc->sc_ethercom.ec_if; | 1606 | struct ifnet *ifp = &sc->sc_ethercom.ec_if; | |
1604 | 1607 | |||
1605 | /* If the frame was not received OK */ | 1608 | /* If the frame was not received OK */ | |
1606 | if (!(rxEvent & RX_EVENT_RX_OK)) { | 1609 | if (!(rxEvent & RX_EVENT_RX_OK)) { | |
1607 | /* Increment the input error count */ | 1610 | /* Increment the input error count */ | |
1608 | ifp->if_ierrors++; | 1611 | if_statinc(ifp, if_ierrors); | |
1609 | 1612 | |||
1610 | /* If debugging is enabled then log error messages. */ | 1613 | /* If debugging is enabled then log error messages. */ | |
1611 | if (ifp->if_flags & IFF_DEBUG) { | 1614 | if (ifp->if_flags & IFF_DEBUG) { | |
1612 | if (rxEvent != REG_NUM_RX_EVENT) { | 1615 | if (rxEvent != REG_NUM_RX_EVENT) { | |
1613 | cs_print_rx_errors(sc, rxEvent); | 1616 | cs_print_rx_errors(sc, rxEvent); | |
1614 | 1617 | |||
1615 | /* | 1618 | /* | |
1616 | * Must read the length of all received | 1619 | * Must read the length of all received | |
1617 | * frames | 1620 | * frames | |
1618 | */ | 1621 | */ | |
1619 | CS_READ_PACKET_PAGE(sc, PKTPG_RX_LENGTH); | 1622 | CS_READ_PACKET_PAGE(sc, PKTPG_RX_LENGTH); | |
1620 | 1623 | |||
1621 | /* Skip the received frame */ | 1624 | /* Skip the received frame */ | |
1622 | CS_WRITE_PACKET_PAGE(sc, PKTPG_RX_CFG, | 1625 | CS_WRITE_PACKET_PAGE(sc, PKTPG_RX_CFG, | |
1623 | CS_READ_PACKET_PAGE(sc, PKTPG_RX_CFG) | | 1626 | CS_READ_PACKET_PAGE(sc, PKTPG_RX_CFG) | | |
1624 | RX_CFG_SKIP); | 1627 | RX_CFG_SKIP); | |
1625 | } else | 1628 | } else | |
1626 | aprint_error_dev(sc->sc_dev, "implied skip\n"); | 1629 | aprint_error_dev(sc->sc_dev, "implied skip\n"); | |
1627 | } | 1630 | } | |
1628 | } else { | 1631 | } else { | |
1629 | /* | 1632 | /* | |
1630 | * Process the received frame and pass it up to the upper | 1633 | * Process the received frame and pass it up to the upper | |
1631 | * layers. | 1634 | * layers. | |
1632 | */ | 1635 | */ | |
1633 | cs_process_receive(sc); | 1636 | cs_process_receive(sc); | |
1634 | } | 1637 | } | |
1635 | } | 1638 | } | |
1636 | 1639 | |||
1637 | void | 1640 | void | |
1638 | cs_ether_input(struct cs_softc *sc, struct mbuf *m) | 1641 | cs_ether_input(struct cs_softc *sc, struct mbuf *m) | |
1639 | { | 1642 | { | |
1640 | struct ifnet *ifp = &sc->sc_ethercom.ec_if; | 1643 | struct ifnet *ifp = &sc->sc_ethercom.ec_if; | |
1641 | 1644 | |||
1642 | /* Pass the packet up. */ | 1645 | /* Pass the packet up. */ | |
1643 | if_percpuq_enqueue(ifp->if_percpuq, m); | 1646 | if_percpuq_enqueue(ifp->if_percpuq, m); | |
1644 | } | 1647 | } | |
1645 | 1648 | |||
1646 | void | 1649 | void | |
1647 | cs_process_receive(struct cs_softc *sc) | 1650 | cs_process_receive(struct cs_softc *sc) | |
1648 | { | 1651 | { | |
1649 | struct ifnet *ifp; | 1652 | struct ifnet *ifp; | |
1650 | struct mbuf *m; | 1653 | struct mbuf *m; | |
1651 | int totlen; | 1654 | int totlen; | |
1652 | uint16_t *pBuff, *pBuffLimit; | 1655 | uint16_t *pBuff, *pBuffLimit; | |
1653 | int pad; | 1656 | int pad; | |
1654 | unsigned int frameOffset = 0; /* XXX: gcc */ | 1657 | unsigned int frameOffset = 0; /* XXX: gcc */ | |
1655 | 1658 | |||
1656 | #ifdef SHARK | 1659 | #ifdef SHARK | |
1657 | ledNetActive(); | 1660 | ledNetActive(); | |
1658 | #endif | 1661 | #endif | |
1659 | 1662 | |||
1660 | ifp = &sc->sc_ethercom.ec_if; | 1663 | ifp = &sc->sc_ethercom.ec_if; | |
1661 | 1664 | |||
1662 | /* Received a packet; carrier is up. */ | 1665 | /* Received a packet; carrier is up. */ | |
1663 | sc->sc_carrier = 1; | 1666 | sc->sc_carrier = 1; | |
1664 | 1667 | |||
1665 | if (sc->sc_memorymode) { | 1668 | if (sc->sc_memorymode) { | |
1666 | /* Initialize the frame offset */ | 1669 | /* Initialize the frame offset */ | |
1667 | frameOffset = PKTPG_RX_LENGTH; | 1670 | frameOffset = PKTPG_RX_LENGTH; | |
1668 | 1671 | |||
1669 | /* Get the length of the received frame */ | 1672 | /* Get the length of the received frame */ | |
1670 | totlen = CS_READ_PACKET_PAGE(sc, frameOffset); | 1673 | totlen = CS_READ_PACKET_PAGE(sc, frameOffset); | |
1671 | frameOffset += 2; | 1674 | frameOffset += 2; | |
1672 | } else { | 1675 | } else { | |
1673 | /* Drop status */ | 1676 | /* Drop status */ | |
1674 | CS_READ_PORT(sc, PORT_RXTX_DATA); | 1677 | CS_READ_PORT(sc, PORT_RXTX_DATA); | |
1675 | 1678 | |||
1676 | /* Get the length of the received frame */ | 1679 | /* Get the length of the received frame */ | |
1677 | totlen = CS_READ_PORT(sc, PORT_RXTX_DATA); | 1680 | totlen = CS_READ_PORT(sc, PORT_RXTX_DATA); | |
1678 | } | 1681 | } | |
1679 | 1682 | |||
1680 | if (totlen > ETHER_MAX_LEN) { | 1683 | if (totlen > ETHER_MAX_LEN) { | |
1681 | aprint_error_dev(sc->sc_dev, "invalid packet length %d\n", | 1684 | aprint_error_dev(sc->sc_dev, "invalid packet length %d\n", | |
1682 | totlen); | 1685 | totlen); | |
1683 | 1686 | |||
1684 | /* Skip the received frame */ | 1687 | /* Skip the received frame */ | |
1685 | CS_WRITE_PACKET_PAGE(sc, PKTPG_RX_CFG, | 1688 | CS_WRITE_PACKET_PAGE(sc, PKTPG_RX_CFG, | |
1686 | CS_READ_PACKET_PAGE(sc, PKTPG_RX_CFG) | RX_CFG_SKIP); | 1689 | CS_READ_PACKET_PAGE(sc, PKTPG_RX_CFG) | RX_CFG_SKIP); | |
1687 | return; | 1690 | return; | |
1688 | } | 1691 | } | |
1689 | 1692 | |||
1690 | MGETHDR(m, M_DONTWAIT, MT_DATA); | 1693 | MGETHDR(m, M_DONTWAIT, MT_DATA); | |
1691 | if (m == 0) { | 1694 | if (m == 0) { | |
1692 | aprint_error_dev(sc->sc_dev, | 1695 | aprint_error_dev(sc->sc_dev, | |
1693 | "cs_process_receive: unable to allocate mbuf\n"); | 1696 | "cs_process_receive: unable to allocate mbuf\n"); | |
1694 | ifp->if_ierrors++; | 1697 | if_statinc(ifp, if_ierrors); | |
1695 | /* | 1698 | /* | |
1696 | * Couldn't allocate an mbuf so things are not good, may as | 1699 | * Couldn't allocate an mbuf so things are not good, may as | |
1697 | * well drop the packet I think. | 1700 | * well drop the packet I think. | |
1698 | * | 1701 | * | |
1699 | * have already read the length so we should be right to skip | 1702 | * have already read the length so we should be right to skip | |
1700 | * the packet. | 1703 | * the packet. | |
1701 | */ | 1704 | */ | |
1702 | CS_WRITE_PACKET_PAGE(sc, PKTPG_RX_CFG, | 1705 | CS_WRITE_PACKET_PAGE(sc, PKTPG_RX_CFG, | |
1703 | CS_READ_PACKET_PAGE(sc, PKTPG_RX_CFG) | RX_CFG_SKIP); | 1706 | CS_READ_PACKET_PAGE(sc, PKTPG_RX_CFG) | RX_CFG_SKIP); | |
1704 | return; | 1707 | return; | |
1705 | } | 1708 | } | |
1706 | m_set_rcvif(m, ifp); | 1709 | m_set_rcvif(m, ifp); | |
1707 | m->m_pkthdr.len = totlen; | 1710 | m->m_pkthdr.len = totlen; | |
1708 | 1711 | |||
1709 | /* Number of bytes to align ip header on word boundary for ipintr */ | 1712 | /* Number of bytes to align ip header on word boundary for ipintr */ | |
1710 | pad = ALIGN(sizeof(struct ether_header)) - sizeof(struct ether_header); | 1713 | pad = ALIGN(sizeof(struct ether_header)) - sizeof(struct ether_header); | |
1711 | 1714 | |||
1712 | /* | 1715 | /* | |
1713 | * Alloc mbuf cluster if we need. | 1716 | * Alloc mbuf cluster if we need. | |
1714 | * We need 1 byte spare because following packet read loop can overrun. | 1717 | * We need 1 byte spare because following packet read loop can overrun. | |
1715 | */ | 1718 | */ | |
1716 | if (totlen + pad + 1 > MHLEN) { | 1719 | if (totlen + pad + 1 > MHLEN) { | |
1717 | MCLGET(m, M_DONTWAIT); | 1720 | MCLGET(m, M_DONTWAIT); | |
1718 | if ((m->m_flags & M_EXT) == 0) { | 1721 | if ((m->m_flags & M_EXT) == 0) { | |
1719 | /* Couldn't allocate an mbuf cluster */ | 1722 | /* Couldn't allocate an mbuf cluster */ | |
1720 | aprint_error_dev(sc->sc_dev, | 1723 | aprint_error_dev(sc->sc_dev, | |
1721 | "cs_process_receive: " | 1724 | "cs_process_receive: " | |
1722 | "unable to allocate a cluster\n"); | 1725 | "unable to allocate a cluster\n"); | |
1723 | m_freem(m); | 1726 | m_freem(m); | |
1724 | 1727 | |||
1725 | /* Skip the received frame */ | 1728 | /* Skip the received frame */ | |
1726 | CS_WRITE_PACKET_PAGE(sc, PKTPG_RX_CFG, | 1729 | CS_WRITE_PACKET_PAGE(sc, PKTPG_RX_CFG, | |
1727 | CS_READ_PACKET_PAGE(sc, PKTPG_RX_CFG) | 1730 | CS_READ_PACKET_PAGE(sc, PKTPG_RX_CFG) | |
1728 | | RX_CFG_SKIP); | 1731 | | RX_CFG_SKIP); | |
1729 | return; | 1732 | return; | |
1730 | } | 1733 | } | |
1731 | } | 1734 | } | |
1732 | 1735 | |||
1733 | /* Align ip header on word boundary for ipintr */ | 1736 | /* Align ip header on word boundary for ipintr */ | |
1734 | m->m_data += pad; | 1737 | m->m_data += pad; | |
1735 | 1738 | |||
1736 | m->m_len = totlen; | 1739 | m->m_len = totlen; | |
1737 | pBuff = mtod(m, uint16_t *); | 1740 | pBuff = mtod(m, uint16_t *); | |
1738 | 1741 | |||
1739 | /* Now read the data from the chip */ | 1742 | /* Now read the data from the chip */ | |
1740 | if (sc->sc_memorymode) { | 1743 | if (sc->sc_memorymode) { | |
1741 | /* Don't want to go over */ | 1744 | /* Don't want to go over */ | |
1742 | pBuffLimit = pBuff + (totlen + 1) / 2; | 1745 | pBuffLimit = pBuff + (totlen + 1) / 2; | |
1743 | 1746 | |||
1744 | while (pBuff < pBuffLimit) { | 1747 | while (pBuff < pBuffLimit) { | |
1745 | *pBuff++ = CS_READ_PACKET_PAGE(sc, frameOffset); | 1748 | *pBuff++ = CS_READ_PACKET_PAGE(sc, frameOffset); | |
1746 | frameOffset += 2; | 1749 | frameOffset += 2; | |
1747 | } | 1750 | } | |
1748 | } else | 1751 | } else | |
1749 | IO_READ_MULTI_2(sc, PORT_RXTX_DATA, pBuff, (totlen + 1)>>1); | 1752 | IO_READ_MULTI_2(sc, PORT_RXTX_DATA, pBuff, (totlen + 1)>>1); | |
1750 | 1753 | |||
1751 | cs_ether_input(sc, m); | 1754 | cs_ether_input(sc, m); | |
1752 | } | 1755 | } | |
1753 | 1756 | |||
1754 | void | 1757 | void | |
1755 | cs_process_rx_early(struct cs_softc *sc) | 1758 | cs_process_rx_early(struct cs_softc *sc) | |
1756 | { | 1759 | { | |
1757 | struct ifnet *ifp; | 1760 | struct ifnet *ifp; | |
1758 | struct mbuf *m; | 1761 | struct mbuf *m; | |
1759 | uint16_t frameCount, oldFrameCount; | 1762 | uint16_t frameCount, oldFrameCount; | |
1760 | uint16_t rxEvent; | 1763 | uint16_t rxEvent; | |
1761 | uint16_t *pBuff; | 1764 | uint16_t *pBuff; | |
1762 | int pad; | 1765 | int pad; | |
1763 | unsigned int frameOffset; | 1766 | unsigned int frameOffset; | |
1764 | 1767 | |||
1765 | 1768 | |||
1766 | ifp = &sc->sc_ethercom.ec_if; | 1769 | ifp = &sc->sc_ethercom.ec_if; | |
1767 | 1770 | |||
1768 | /* Initialize the frame offset */ | 1771 | /* Initialize the frame offset */ | |
1769 | frameOffset = PKTPG_RX_FRAME; | 1772 | frameOffset = PKTPG_RX_FRAME; | |
1770 | frameCount = 0; | 1773 | frameCount = 0; | |
1771 | 1774 | |||
1772 | MGETHDR(m, M_DONTWAIT, MT_DATA); | 1775 | MGETHDR(m, M_DONTWAIT, MT_DATA); | |
1773 | if (m == 0) { | 1776 | if (m == 0) { | |
1774 | aprint_error_dev(sc->sc_dev, | 1777 | aprint_error_dev(sc->sc_dev, | |
1775 | "cs_process_rx_early: unable to allocate mbuf\n"); | 1778 | "cs_process_rx_early: unable to allocate mbuf\n"); | |
1776 | ifp->if_ierrors++; | 1779 | if_statinc(ifp, if_ierrors); | |
1777 | /* | 1780 | /* | |
1778 | * Couldn't allocate an mbuf so things are not good, may as | 1781 | * Couldn't allocate an mbuf so things are not good, may as | |
1779 | * well drop the packet I think. | 1782 | * well drop the packet I think. | |
1780 | * | 1783 | * | |
1781 | * have already read the length so we should be right to skip | 1784 | * have already read the length so we should be right to skip | |
1782 | * the packet. | 1785 | * the packet. | |
1783 | */ | 1786 | */ | |
1784 | CS_WRITE_PACKET_PAGE(sc, PKTPG_RX_CFG, | 1787 | CS_WRITE_PACKET_PAGE(sc, PKTPG_RX_CFG, | |
1785 | CS_READ_PACKET_PAGE(sc, PKTPG_RX_CFG) | RX_CFG_SKIP); | 1788 | CS_READ_PACKET_PAGE(sc, PKTPG_RX_CFG) | RX_CFG_SKIP); | |
1786 | return; | 1789 | return; | |
1787 | } | 1790 | } | |
1788 | m_set_rcvif(m, ifp); | 1791 | m_set_rcvif(m, ifp); | |
1789 | /* | 1792 | /* | |
1790 | * Save processing by always using a mbuf cluster, guaranteed to fit | 1793 | * Save processing by always using a mbuf cluster, guaranteed to fit | |
1791 | * packet | 1794 | * packet | |
1792 | */ | 1795 | */ | |
1793 | MCLGET(m, M_DONTWAIT); | 1796 | MCLGET(m, M_DONTWAIT); | |
1794 | if ((m->m_flags & M_EXT) == 0) { | 1797 | if ((m->m_flags & M_EXT) == 0) { | |
1795 | /* Couldn't allocate an mbuf cluster */ | 1798 | /* Couldn't allocate an mbuf cluster */ | |
1796 | aprint_error_dev(sc->sc_dev, | 1799 | aprint_error_dev(sc->sc_dev, | |
1797 | "cs_process_rx_early: unable to allocate a cluster\n"); | 1800 | "cs_process_rx_early: unable to allocate a cluster\n"); | |
1798 | m_freem(m); | 1801 | m_freem(m); | |
1799 | /* Skip the frame */ | 1802 | /* Skip the frame */ | |
1800 | CS_WRITE_PACKET_PAGE(sc, PKTPG_RX_CFG, | 1803 | CS_WRITE_PACKET_PAGE(sc, PKTPG_RX_CFG, | |
1801 | CS_READ_PACKET_PAGE(sc, PKTPG_RX_CFG) | RX_CFG_SKIP); | 1804 | CS_READ_PACKET_PAGE(sc, PKTPG_RX_CFG) | RX_CFG_SKIP); | |
1802 | return; | 1805 | return; | |
1803 | } | 1806 | } | |
1804 | 1807 | |||
1805 | /* Align ip header on word boundary for ipintr */ | 1808 | /* Align ip header on word boundary for ipintr */ | |
1806 | pad = ALIGN(sizeof(struct ether_header)) - sizeof(struct ether_header); | 1809 | pad = ALIGN(sizeof(struct ether_header)) - sizeof(struct ether_header); | |
1807 | m->m_data += pad; | 1810 | m->m_data += pad; | |
1808 | 1811 | |||
1809 | /* Set up the buffer pointer to point to the data area */ | 1812 | /* Set up the buffer pointer to point to the data area */ | |
1810 | pBuff = mtod(m, uint16_t *); | 1813 | pBuff = mtod(m, uint16_t *); | |
1811 | 1814 | |||
1812 | /* | 1815 | /* | |
1813 | * Now read the frame byte counter until we have finished reading the | 1816 | * Now read the frame byte counter until we have finished reading the | |
1814 | * frame | 1817 | * frame | |
1815 | */ | 1818 | */ | |
1816 | oldFrameCount = 0; | 1819 | oldFrameCount = 0; | |
1817 | frameCount = CS_READ_PACKET_PAGE(sc, PKTPG_FRAME_BYTE_COUNT); | 1820 | frameCount = CS_READ_PACKET_PAGE(sc, PKTPG_FRAME_BYTE_COUNT); | |
1818 | while ((frameCount != 0) && (frameCount < MCLBYTES)) { | 1821 | while ((frameCount != 0) && (frameCount < MCLBYTES)) { | |
1819 | for (; oldFrameCount < frameCount; oldFrameCount += 2) { | 1822 | for (; oldFrameCount < frameCount; oldFrameCount += 2) { | |
1820 | *pBuff++ = CS_READ_PACKET_PAGE(sc, frameOffset); | 1823 | *pBuff++ = CS_READ_PACKET_PAGE(sc, frameOffset); | |
1821 | frameOffset += 2; | 1824 | frameOffset += 2; | |
1822 | } | 1825 | } | |
1823 | 1826 | |||
1824 | /* Read the new count from the chip */ | 1827 | /* Read the new count from the chip */ | |
1825 | frameCount = CS_READ_PACKET_PAGE(sc, PKTPG_FRAME_BYTE_COUNT); | 1828 | frameCount = CS_READ_PACKET_PAGE(sc, PKTPG_FRAME_BYTE_COUNT); | |
1826 | } | 1829 | } | |
1827 | 1830 | |||
1828 | /* Update the mbuf counts */ | 1831 | /* Update the mbuf counts */ | |
1829 | m->m_len = oldFrameCount; | 1832 | m->m_len = oldFrameCount; | |
1830 | m->m_pkthdr.len = oldFrameCount; | 1833 | m->m_pkthdr.len = oldFrameCount; | |
1831 | 1834 | |||
1832 | /* Now check the Rx Event register */ | 1835 | /* Now check the Rx Event register */ | |
1833 | rxEvent = CS_READ_PACKET_PAGE(sc, PKTPG_RX_EVENT); | 1836 | rxEvent = CS_READ_PACKET_PAGE(sc, PKTPG_RX_EVENT); | |
1834 | 1837 | |||
1835 | if ((rxEvent & RX_EVENT_RX_OK) != 0) { | 1838 | if ((rxEvent & RX_EVENT_RX_OK) != 0) { | |
1836 | /* | 1839 | /* | |
1837 | * Do an implied skip, it seems to be more reliable than a | 1840 | * Do an implied skip, it seems to be more reliable than a | |
1838 | * forced skip. | 1841 | * forced skip. | |
1839 | */ | 1842 | */ | |
1840 | rxEvent = CS_READ_PACKET_PAGE(sc, PKTPG_RX_STATUS); | 1843 | rxEvent = CS_READ_PACKET_PAGE(sc, PKTPG_RX_STATUS); | |
1841 | rxEvent = CS_READ_PACKET_PAGE(sc, PKTPG_RX_LENGTH); | 1844 | rxEvent = CS_READ_PACKET_PAGE(sc, PKTPG_RX_LENGTH); | |
1842 | 1845 | |||
1843 | /* | 1846 | /* | |
1844 | * Now read the RX_EVENT register to perform an implied skip. | 1847 | * Now read the RX_EVENT register to perform an implied skip. | |
1845 | */ | 1848 | */ | |
1846 | rxEvent = CS_READ_PACKET_PAGE(sc, PKTPG_RX_EVENT); | 1849 | rxEvent = CS_READ_PACKET_PAGE(sc, PKTPG_RX_EVENT); | |
1847 | 1850 | |||
1848 | cs_ether_input(sc, m); | 1851 | cs_ether_input(sc, m); | |
1849 | } else { | 1852 | } else { | |
1850 | m_freem(m); | 1853 | m_freem(m); | |
1851 | ifp->if_ierrors++; | 1854 | if_statinc(ifp, if_ierrors); | |
1852 | } | 1855 | } | |
1853 | } | 1856 | } | |
1854 | 1857 | |||
1855 | void | 1858 | void | |
1856 | cs_start_output(struct ifnet *ifp) | 1859 | cs_start_output(struct ifnet *ifp) | |
1857 | { | 1860 | { | |
1858 | struct cs_softc *sc; | 1861 | struct cs_softc *sc; | |
1859 | struct mbuf *pMbuf; | 1862 | struct mbuf *pMbuf; | |
1860 | struct mbuf *pMbufChain; | 1863 | struct mbuf *pMbufChain; | |
1861 | uint16_t BusStatus; | 1864 | uint16_t BusStatus; | |
1862 | uint16_t Length; | 1865 | uint16_t Length; | |
1863 | int txLoop = 0; | 1866 | int txLoop = 0; | |
1864 | int dropout = 0; | 1867 | int dropout = 0; | |
1865 | 1868 | |||
1866 | sc = ifp->if_softc; | 1869 | sc = ifp->if_softc; | |
1867 | 1870 | |||
1868 | /* Check that the interface is up and running */ | 1871 | /* Check that the interface is up and running */ | |
1869 | if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING) | 1872 | if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING) | |
1870 | return; | 1873 | return; | |
1871 | 1874 | |||
1872 | /* Don't interrupt a transmission in progress */ | 1875 | /* Don't interrupt a transmission in progress */ | |
1873 | if (sc->sc_txbusy) | 1876 | if (sc->sc_txbusy) | |
1874 | return; | 1877 | return; | |
1875 | 1878 | |||
1876 | /* This loop will only run through once if transmission is successful */ | 1879 | /* This loop will only run through once if transmission is successful */ | |
1877 | /* | 1880 | /* | |
1878 | * While there are packets to transmit and a transmit is not in | 1881 | * While there are packets to transmit and a transmit is not in | |
1879 | * progress | 1882 | * progress | |
1880 | */ | 1883 | */ | |
1881 | while (sc->sc_txbusy == 0 && dropout == 0) { | 1884 | while (sc->sc_txbusy == 0 && dropout == 0) { | |
1882 | IFQ_DEQUEUE(&ifp->if_snd, pMbufChain); | 1885 | IFQ_DEQUEUE(&ifp->if_snd, pMbufChain); | |
1883 | if (pMbufChain == NULL) | 1886 | if (pMbufChain == NULL) | |
1884 | break; | 1887 | break; | |
1885 | 1888 | |||
1886 | /* | 1889 | /* | |
1887 | * If BPF is listening on this interface, let it see the packet | 1890 | * If BPF is listening on this interface, let it see the packet | |
1888 | * before we commit it to the wire. | 1891 | * before we commit it to the wire. | |
1889 | */ | 1892 | */ | |
1890 | bpf_mtap(ifp, pMbufChain, BPF_D_OUT); | 1893 | bpf_mtap(ifp, pMbufChain, BPF_D_OUT); | |
1891 | 1894 | |||
1892 | /* Find the total length of the data to transmit */ | 1895 | /* Find the total length of the data to transmit */ | |
1893 | Length = 0; | 1896 | Length = 0; | |
1894 | for (pMbuf = pMbufChain; pMbuf != NULL; pMbuf = pMbuf->m_next) | 1897 | for (pMbuf = pMbufChain; pMbuf != NULL; pMbuf = pMbuf->m_next) | |
1895 | Length += pMbuf->m_len; | 1898 | Length += pMbuf->m_len; | |
1896 | 1899 | |||
1897 | do { | 1900 | do { | |
1898 | /* | 1901 | /* | |
1899 | * Request that the transmit be started after all | 1902 | * Request that the transmit be started after all | |
1900 | * data has been copied | 1903 | * data has been copied | |
1901 | * | 1904 | * | |
1902 | * In IO mode must write to the IO port not the packet | 1905 | * In IO mode must write to the IO port not the packet | |
1903 | * page address | 1906 | * page address | |
1904 | * | 1907 | * | |
1905 | * If this is changed to start transmission after a | 1908 | * If this is changed to start transmission after a | |
1906 | * small amount of data has been copied you tend to | 1909 | * small amount of data has been copied you tend to | |
1907 | * get packet missed errors i think because the ISA | 1910 | * get packet missed errors i think because the ISA | |
1908 | * bus is too slow. Or possibly the copy routine is | 1911 | * bus is too slow. Or possibly the copy routine is | |
1909 | * not streamlined enough. | 1912 | * not streamlined enough. | |
1910 | */ | 1913 | */ | |
1911 | if (sc->sc_memorymode) { | 1914 | if (sc->sc_memorymode) { | |
1912 | CS_WRITE_PACKET_PAGE(sc, PKTPG_TX_CMD, | 1915 | CS_WRITE_PACKET_PAGE(sc, PKTPG_TX_CMD, | |
1913 | cs_xmit_early_table[sc->sc_xe_ent].txcmd); | 1916 | cs_xmit_early_table[sc->sc_xe_ent].txcmd); | |
1914 | CS_WRITE_PACKET_PAGE(sc, PKTPG_TX_LENGTH, Length); | 1917 | CS_WRITE_PACKET_PAGE(sc, PKTPG_TX_LENGTH, Length); | |
1915 | } else { | 1918 | } else { | |
1916 | CS_WRITE_PORT(sc, PORT_TX_CMD, | 1919 | CS_WRITE_PORT(sc, PORT_TX_CMD, | |
1917 | cs_xmit_early_table[sc->sc_xe_ent].txcmd); | 1920 | cs_xmit_early_table[sc->sc_xe_ent].txcmd); | |
1918 | CS_WRITE_PORT(sc, PORT_TX_LENGTH, Length); | 1921 | CS_WRITE_PORT(sc, PORT_TX_LENGTH, Length); | |
1919 | } | 1922 | } | |
1920 | 1923 | |||
1921 | /* Adjust early-transmit machinery. */ | 1924 | /* Adjust early-transmit machinery. */ | |
1922 | if (--sc->sc_xe_togo == 0) { | 1925 | if (--sc->sc_xe_togo == 0) { | |
1923 | sc->sc_xe_ent = | 1926 | sc->sc_xe_ent = | |
1924 | cs_xmit_early_table[sc->sc_xe_ent].better; | 1927 | cs_xmit_early_table[sc->sc_xe_ent].better; | |
1925 | sc->sc_xe_togo = | 1928 | sc->sc_xe_togo = | |
1926 | cs_xmit_early_table[sc->sc_xe_ent].better_count; | 1929 | cs_xmit_early_table[sc->sc_xe_ent].better_count; | |
1927 | } | 1930 | } | |
1928 | /* | 1931 | /* | |
1929 | * Read the BusStatus register which indicates | 1932 | * Read the BusStatus register which indicates | |
1930 | * success of the request | 1933 | * success of the request | |
1931 | */ | 1934 | */ | |
1932 | BusStatus = CS_READ_PACKET_PAGE(sc, PKTPG_BUS_ST); | 1935 | BusStatus = CS_READ_PACKET_PAGE(sc, PKTPG_BUS_ST); | |
1933 | 1936 | |||
1934 | /* | 1937 | /* | |
1935 | * If there was an error in the transmit bid free the | 1938 | * If there was an error in the transmit bid free the | |
1936 | * mbuf and go on. This is presuming that mbuf is | 1939 | * mbuf and go on. This is presuming that mbuf is | |
1937 | * corrupt. | 1940 | * corrupt. | |
1938 | */ | 1941 | */ | |
1939 | if (BusStatus & BUS_ST_TX_BID_ERR) { | 1942 | if (BusStatus & BUS_ST_TX_BID_ERR) { | |
1940 | aprint_error_dev(sc->sc_dev, | 1943 | aprint_error_dev(sc->sc_dev, | |
1941 | "transmit bid error (too big)"); | 1944 | "transmit bid error (too big)"); | |
1942 | 1945 | |||
1943 | /* Discard the bad mbuf chain */ | 1946 | /* Discard the bad mbuf chain */ | |
1944 | m_freem(pMbufChain); | 1947 | m_freem(pMbufChain); | |
1945 | sc->sc_ethercom.ec_if.if_oerrors++; | 1948 | if_statinc(&sc->sc_ethercom.ec_if, if_oerrors); | |
1946 | 1949 | |||
1947 | /* Loop up to transmit the next chain */ | 1950 | /* Loop up to transmit the next chain */ | |
1948 | txLoop = 0; | 1951 | txLoop = 0; | |
1949 | } else { | 1952 | } else { | |
1950 | if (BusStatus & BUS_ST_RDY4TXNOW) { | 1953 | if (BusStatus & BUS_ST_RDY4TXNOW) { | |
1951 | /* | 1954 | /* | |
1952 | * The chip is ready for transmission | 1955 | * The chip is ready for transmission | |
1953 | * now | 1956 | * now | |
1954 | */ | 1957 | */ | |
1955 | /* | 1958 | /* | |
1956 | * Copy the frame to the chip to | 1959 | * Copy the frame to the chip to | |
1957 | * start transmission | 1960 | * start transmission | |
1958 | */ | 1961 | */ | |
1959 | cs_copy_tx_frame(sc, pMbufChain); | 1962 | cs_copy_tx_frame(sc, pMbufChain); | |
1960 | 1963 | |||
1961 | /* Free the mbuf chain */ | 1964 | /* Free the mbuf chain */ | |
1962 | m_freem(pMbufChain); | 1965 | m_freem(pMbufChain); | |
1963 | 1966 | |||
1964 | /* Transmission is now in progress */ | 1967 | /* Transmission is now in progress */ | |
1965 | sc->sc_txbusy = TRUE; | 1968 | sc->sc_txbusy = TRUE; | |
1966 | txLoop = 0; | 1969 | txLoop = 0; | |
1967 | } else { | 1970 | } else { | |
1968 | /* | 1971 | /* | |
1969 | * If we get here we want to try | 1972 | * If we get here we want to try | |
1970 | * again with the same mbuf, until | 1973 | * again with the same mbuf, until | |
1971 | * the chip lets us transmit. | 1974 | * the chip lets us transmit. | |
1972 | */ | 1975 | */ | |
1973 | txLoop++; | 1976 | txLoop++; | |
1974 | if (txLoop > CS_OUTPUT_LOOP_MAX) { | 1977 | if (txLoop > CS_OUTPUT_LOOP_MAX) { | |
1975 | /* Free the mbuf chain */ | 1978 | /* Free the mbuf chain */ | |
1976 | m_freem(pMbufChain); | 1979 | m_freem(pMbufChain); | |
1977 | /* | 1980 | /* | |
1978 | * Transmission is not in | 1981 | * Transmission is not in | |
1979 | * progress | 1982 | * progress | |
1980 | */ | 1983 | */ | |
1981 | sc->sc_txbusy = FALSE; | 1984 | sc->sc_txbusy = FALSE; | |
1982 | /* | 1985 | /* | |
1983 | * Increment the output error | 1986 | * Increment the output error | |
1984 | * count | 1987 | * count | |
1985 | */ | 1988 | */ | |
1986 | ifp->if_oerrors++; | 1989 | if_statinc(ifp, if_oerrors); | |
1987 | /* | 1990 | /* | |
1988 | * exit the routine and drop | 1991 | * exit the routine and drop | |
1989 | * the packet. | 1992 | * the packet. | |
1990 | */ | 1993 | */ | |
1991 | txLoop = 0; | 1994 | txLoop = 0; | |
1992 | dropout = 1; | 1995 | dropout = 1; | |
1993 | } | 1996 | } | |
1994 | } | 1997 | } | |
1995 | } | 1998 | } | |
1996 | } while (txLoop); | 1999 | } while (txLoop); | |
1997 | } | 2000 | } | |
1998 | } | 2001 | } | |
1999 | 2002 | |||
2000 | void | 2003 | void | |
2001 | cs_copy_tx_frame(struct cs_softc *sc, struct mbuf *m0) | 2004 | cs_copy_tx_frame(struct cs_softc *sc, struct mbuf *m0) | |
2002 | { | 2005 | { | |
2003 | struct mbuf *m; | 2006 | struct mbuf *m; | |
2004 | int len, leftover, frameoff; | 2007 | int len, leftover, frameoff; | |
2005 | uint16_t dbuf; | 2008 | uint16_t dbuf; | |
2006 | uint8_t *p; | 2009 | uint8_t *p; | |
2007 | #ifdef DIAGNOSTIC | 2010 | #ifdef DIAGNOSTIC | |
2008 | uint8_t *lim; | 2011 | uint8_t *lim; | |
2009 | #endif | 2012 | #endif | |
2010 | 2013 | |||
2011 | /* Initialize frame pointer and data port address */ | 2014 | /* Initialize frame pointer and data port address */ | |
2012 | frameoff = PKTPG_TX_FRAME; | 2015 | frameoff = PKTPG_TX_FRAME; | |
2013 | 2016 | |||
2014 | /* Start out with no leftover data */ | 2017 | /* Start out with no leftover data */ | |
2015 | leftover = 0; | 2018 | leftover = 0; | |
2016 | dbuf = 0; | 2019 | dbuf = 0; | |
2017 | 2020 | |||
2018 | /* Process the chain of mbufs */ | 2021 | /* Process the chain of mbufs */ | |
2019 | for (m = m0; m != NULL; m = m->m_next) { | 2022 | for (m = m0; m != NULL; m = m->m_next) { | |
2020 | /* Process all of the data in a single mbuf. */ | 2023 | /* Process all of the data in a single mbuf. */ | |
2021 | p = mtod(m, uint8_t *); | 2024 | p = mtod(m, uint8_t *); | |
2022 | len = m->m_len; | 2025 | len = m->m_len; | |
2023 | #ifdef DIAGNOSTIC | 2026 | #ifdef DIAGNOSTIC | |
2024 | lim = p + len; | 2027 | lim = p + len; | |
2025 | #endif | 2028 | #endif | |
2026 | 2029 | |||
2027 | while (len > 0) { | 2030 | while (len > 0) { | |
2028 | if (leftover) { | 2031 | if (leftover) { | |
2029 | /* | 2032 | /* | |
2030 | * Data left over (from mbuf or realignment). | 2033 | * Data left over (from mbuf or realignment). | |
2031 | * Buffer the next byte, and write it and | 2034 | * Buffer the next byte, and write it and | |
2032 | * the leftover data out. | 2035 | * the leftover data out. | |
2033 | */ | 2036 | */ | |
2034 | dbuf |= *p++ << 8; | 2037 | dbuf |= *p++ << 8; | |
2035 | len--; | 2038 | len--; | |
2036 | if (sc->sc_memorymode) { | 2039 | if (sc->sc_memorymode) { | |
2037 | CS_WRITE_PACKET_PAGE(sc, frameoff, dbuf); | 2040 | CS_WRITE_PACKET_PAGE(sc, frameoff, dbuf); | |
2038 | frameoff += 2; | 2041 | frameoff += 2; | |
2039 | } | 2042 | } | |
2040 | else { | 2043 | else { | |
2041 | CS_WRITE_PORT(sc, PORT_RXTX_DATA, dbuf); | 2044 | CS_WRITE_PORT(sc, PORT_RXTX_DATA, dbuf); | |
2042 | } | 2045 | } | |
2043 | leftover = 0; | 2046 | leftover = 0; | |
2044 | } else if ((long) p & 1) { | 2047 | } else if ((long) p & 1) { | |
2045 | /* Misaligned data. Buffer the next byte. */ | 2048 | /* Misaligned data. Buffer the next byte. */ | |
2046 | dbuf = *p++; | 2049 | dbuf = *p++; | |
2047 | len--; | 2050 | len--; | |
2048 | leftover = 1; | 2051 | leftover = 1; | |
2049 | } else { | 2052 | } else { | |
2050 | /* | 2053 | /* | |
2051 | * Aligned data. This is the case we like. | 2054 | * Aligned data. This is the case we like. | |
2052 | * | 2055 | * | |
2053 | * Write-region out as much as we can, then | 2056 | * Write-region out as much as we can, then | |
2054 | * buffer the remaining byte (if any). | 2057 | * buffer the remaining byte (if any). | |
2055 | */ | 2058 | */ | |
2056 | leftover = len & 1; | 2059 | leftover = len & 1; | |
2057 | len &= ~1; | 2060 | len &= ~1; | |
2058 | if (sc->sc_memorymode) { | 2061 | if (sc->sc_memorymode) { | |
2059 | MEM_WRITE_REGION_2(sc, frameoff, | 2062 | MEM_WRITE_REGION_2(sc, frameoff, | |
2060 | (uint16_t *) p, len >> 1); | 2063 | (uint16_t *) p, len >> 1); | |
2061 | frameoff += len; | 2064 | frameoff += len; | |
2062 | } else | 2065 | } else | |
2063 | IO_WRITE_MULTI_2(sc, PORT_RXTX_DATA, | 2066 | IO_WRITE_MULTI_2(sc, PORT_RXTX_DATA, | |
2064 | (uint16_t *)p, len >> 1); | 2067 | (uint16_t *)p, len >> 1); | |
2065 | p += len; | 2068 | p += len; | |
2066 | 2069 | |||
2067 | if (leftover) | 2070 | if (leftover) | |
2068 | dbuf = *p++; | 2071 | dbuf = *p++; | |
2069 | len = 0; | 2072 | len = 0; | |
2070 | } | 2073 | } | |
2071 | } | 2074 | } | |
2072 | if (len < 0) | 2075 | if (len < 0) | |
2073 | panic("cs_copy_tx_frame: negative len"); | 2076 | panic("cs_copy_tx_frame: negative len"); | |
2074 | #ifdef DIAGNOSTIC | 2077 | #ifdef DIAGNOSTIC | |
2075 | if (p != lim) | 2078 | if (p != lim) | |
2076 | panic("cs_copy_tx_frame: p != lim"); | 2079 | panic("cs_copy_tx_frame: p != lim"); | |
2077 | #endif | 2080 | #endif | |
2078 | } | 2081 | } | |
2079 | if (leftover) { | 2082 | if (leftover) { | |
2080 | if (sc->sc_memorymode) | 2083 | if (sc->sc_memorymode) | |
2081 | CS_WRITE_PACKET_PAGE(sc, frameoff, dbuf); | 2084 | CS_WRITE_PACKET_PAGE(sc, frameoff, dbuf); | |
2082 | else | 2085 | else | |
2083 | CS_WRITE_PORT(sc, PORT_RXTX_DATA, dbuf); | 2086 | CS_WRITE_PORT(sc, PORT_RXTX_DATA, dbuf); | |
2084 | } | 2087 | } | |
2085 | } | 2088 | } | |
2086 | 2089 | |||
2087 | static int | 2090 | static int | |
2088 | cs_enable(struct cs_softc *sc) | 2091 | cs_enable(struct cs_softc *sc) | |
2089 | { | 2092 | { | |
2090 | 2093 | |||
2091 | if (CS_IS_ENABLED(sc) == 0) { | 2094 | if (CS_IS_ENABLED(sc) == 0) { | |
2092 | if (sc->sc_enable != NULL) { | 2095 | if (sc->sc_enable != NULL) { | |
2093 | int error; | 2096 | int error; | |
2094 | 2097 | |||
2095 | error = (*sc->sc_enable)(sc); | 2098 | error = (*sc->sc_enable)(sc); | |
2096 | if (error) | 2099 | if (error) | |
2097 | return error; | 2100 | return error; | |
2098 | } | 2101 | } | |
2099 | sc->sc_cfgflags |= CFGFLG_ENABLED; | 2102 | sc->sc_cfgflags |= CFGFLG_ENABLED; | |
2100 | } | 2103 | } | |
2101 | 2104 | |||
2102 | return 0; | 2105 | return 0; | |
2103 | } | 2106 | } | |
2104 | 2107 | |||
2105 | static void | 2108 | static void | |
2106 | cs_disable(struct cs_softc *sc) | 2109 | cs_disable(struct cs_softc *sc) | |
2107 | { | 2110 | { | |
2108 | 2111 | |||
2109 | if (CS_IS_ENABLED(sc)) { | 2112 | if (CS_IS_ENABLED(sc)) { | |
2110 | if (sc->sc_disable != NULL) | 2113 | if (sc->sc_disable != NULL) | |
2111 | (*sc->sc_disable)(sc); | 2114 | (*sc->sc_disable)(sc); | |
2112 | 2115 | |||
2113 | sc->sc_cfgflags &= ~CFGFLG_ENABLED; | 2116 | sc->sc_cfgflags &= ~CFGFLG_ENABLED; | |
2114 | } | 2117 | } | |
2115 | } | 2118 | } | |
2116 | 2119 | |||
2117 | static void | 2120 | static void | |
2118 | cs_stop(struct ifnet *ifp, int disable) | 2121 | cs_stop(struct ifnet *ifp, int disable) | |
2119 | { | 2122 | { | |
2120 | struct cs_softc *sc = ifp->if_softc; | 2123 | struct cs_softc *sc = ifp->if_softc; | |
2121 | 2124 | |||
2122 | CS_WRITE_PACKET_PAGE(sc, PKTPG_RX_CFG, 0); | 2125 | CS_WRITE_PACKET_PAGE(sc, PKTPG_RX_CFG, 0); | |
2123 | CS_WRITE_PACKET_PAGE(sc, PKTPG_TX_CFG, 0); | 2126 | CS_WRITE_PACKET_PAGE(sc, PKTPG_TX_CFG, 0); | |
2124 | CS_WRITE_PACKET_PAGE(sc, PKTPG_BUF_CFG, 0); | 2127 | CS_WRITE_PACKET_PAGE(sc, PKTPG_BUF_CFG, 0); | |
2125 | CS_WRITE_PACKET_PAGE(sc, PKTPG_BUS_CTL, 0); | 2128 | CS_WRITE_PACKET_PAGE(sc, PKTPG_BUS_CTL, 0); | |
2126 | 2129 | |||
2127 | if (disable) | 2130 | if (disable) | |
2128 | cs_disable(sc); | 2131 | cs_disable(sc); | |
2129 | 2132 | |||
2130 | ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); | 2133 | ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); | |
2131 | } | 2134 | } | |
2132 | 2135 | |||
2133 | int | 2136 | int | |
2134 | cs_activate(device_t self, enum devact act) | 2137 | cs_activate(device_t self, enum devact act) | |
2135 | { | 2138 | { | |
2136 | struct cs_softc *sc = device_private(self); | 2139 | struct cs_softc *sc = device_private(self); | |
2137 | 2140 | |||
2138 | switch (act) { | 2141 | switch (act) { | |
2139 | case DVACT_DEACTIVATE: | 2142 | case DVACT_DEACTIVATE: | |
2140 | if_deactivate(&sc->sc_ethercom.ec_if); | 2143 | if_deactivate(&sc->sc_ethercom.ec_if); | |
2141 | return 0; | 2144 | return 0; | |
2142 | default: | 2145 | default: | |
2143 | return EOPNOTSUPP; | 2146 | return EOPNOTSUPP; | |
2144 | } | 2147 | } | |
2145 | } | 2148 | } |
--- src/sys/dev/ic/dm9000.c 2019/05/29 10:07:29 1.21
+++ src/sys/dev/ic/dm9000.c 2020/01/29 14:14:55 1.22
@@ -1,1229 +1,1229 @@ | @@ -1,1229 +1,1229 @@ | |||
1 | /* $NetBSD: dm9000.c,v 1.21 2019/05/29 10:07:29 msaitoh Exp $ */ | 1 | /* $NetBSD: dm9000.c,v 1.22 2020/01/29 14:14:55 thorpej Exp $ */ | |
2 | 2 | |||
3 | /* | 3 | /* | |
4 | * Copyright (c) 2009 Paul Fleischer | 4 | * Copyright (c) 2009 Paul Fleischer | |
5 | * All rights reserved. | 5 | * All rights reserved. | |
6 | * | 6 | * | |
7 | * 1. Redistributions of source code must retain the above copyright | 7 | * 1. Redistributions of source code must retain the above copyright | |
8 | * notice, this list of conditions and the following disclaimer. | 8 | * notice, this list of conditions and the following disclaimer. | |
9 | * 2. Redistributions in binary form must reproduce the above copyright | 9 | * 2. Redistributions in binary form must reproduce the above copyright | |
10 | * notice, this list of conditions and the following disclaimer in the | 10 | * notice, this list of conditions and the following disclaimer in the | |
11 | * documentation and/or other materials provided with the distribution. | 11 | * documentation and/or other materials provided with the distribution. | |
12 | * 3. The name of the company nor the name of the author may be used to | 12 | * 3. The name of the company nor the name of the author may be used to | |
13 | * endorse or promote products derived from this software without specific | 13 | * endorse or promote products derived from this software without specific | |
14 | * prior written permission. | 14 | * prior written permission. | |
15 | * | 15 | * | |
16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED | 16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED | |
17 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | 17 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |
18 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | 18 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | |
19 | * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, | 19 | * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, | |
20 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | 20 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | |
22 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | 22 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
23 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | 23 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
24 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 24 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
25 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 25 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
26 | * SUCH DAMAGE. | 26 | * SUCH DAMAGE. | |
27 | */ | 27 | */ | |
28 | 28 | |||
29 | /* based on sys/dev/ic/cs89x0.c */ | 29 | /* based on sys/dev/ic/cs89x0.c */ | |
30 | /* | 30 | /* | |
31 | * Copyright (c) 2004 Christopher Gilbert | 31 | * Copyright (c) 2004 Christopher Gilbert | |
32 | * All rights reserved. | 32 | * All rights reserved. | |
33 | * | 33 | * | |
34 | * 1. Redistributions of source code must retain the above copyright | 34 | * 1. Redistributions of source code must retain the above copyright | |
35 | * notice, this list of conditions and the following disclaimer. | 35 | * notice, this list of conditions and the following disclaimer. | |
36 | * 2. Redistributions in binary form must reproduce the above copyright | 36 | * 2. Redistributions in binary form must reproduce the above copyright | |
37 | * notice, this list of conditions and the following disclaimer in the | 37 | * notice, this list of conditions and the following disclaimer in the | |
38 | * documentation and/or other materials provided with the distribution. | 38 | * documentation and/or other materials provided with the distribution. | |
39 | * 3. The name of the company nor the name of the author may be used to | 39 | * 3. The name of the company nor the name of the author may be used to | |
40 | * endorse or promote products derived from this software without specific | 40 | * endorse or promote products derived from this software without specific | |
41 | * prior written permission. | 41 | * prior written permission. | |
42 | * | 42 | * | |
43 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED | 43 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED | |
44 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | 44 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |
45 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | 45 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | |
46 | * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, | 46 | * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, | |
47 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | 47 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
48 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | 48 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | |
49 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | 49 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
50 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | 50 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
51 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 51 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
52 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 52 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
53 | * SUCH DAMAGE. | 53 | * SUCH DAMAGE. | |
54 | */ | 54 | */ | |
55 | 55 | |||
56 | /* | 56 | /* | |
57 | * Copyright 1997 | 57 | * Copyright 1997 | |
58 | * Digital Equipment Corporation. All rights reserved. | 58 | * Digital Equipment Corporation. All rights reserved. | |
59 | * | 59 | * | |
60 | * This software is furnished under license and may be used and | 60 | * This software is furnished under license and may be used and | |
61 | * copied only in accordance with the following terms and conditions. | 61 | * copied only in accordance with the following terms and conditions. | |
62 | * Subject to these conditions, you may download, copy, install, | 62 | * Subject to these conditions, you may download, copy, install, | |
63 | * use, modify and distribute this software in source and/or binary | 63 | * use, modify and distribute this software in source and/or binary | |
64 | * form. No title or ownership is transferred hereby. | 64 | * form. No title or ownership is transferred hereby. | |
65 | * | 65 | * | |
66 | * 1) Any source code used, modified or distributed must reproduce | 66 | * 1) Any source code used, modified or distributed must reproduce | |
67 | * and retain this copyright notice and list of conditions as | 67 | * and retain this copyright notice and list of conditions as | |
68 | * they appear in the source file. | 68 | * they appear in the source file. | |
69 | * | 69 | * | |
70 | * 2) No right is granted to use any trade name, trademark, or logo of | 70 | * 2) No right is granted to use any trade name, trademark, or logo of | |
71 | * Digital Equipment Corporation. Neither the "Digital Equipment | 71 | * Digital Equipment Corporation. Neither the "Digital Equipment | |
72 | * Corporation" name nor any trademark or logo of Digital Equipment | 72 | * Corporation" name nor any trademark or logo of Digital Equipment | |
73 | * Corporation may be used to endorse or promote products derived | 73 | * Corporation may be used to endorse or promote products derived | |
74 | * from this software without the prior written permission of | 74 | * from this software without the prior written permission of | |
75 | * Digital Equipment Corporation. | 75 | * Digital Equipment Corporation. | |
76 | * | 76 | * | |
77 | * 3) This software is provided "AS-IS" and any express or implied | 77 | * 3) This software is provided "AS-IS" and any express or implied | |
78 | * warranties, including but not limited to, any implied warranties | 78 | * warranties, including but not limited to, any implied warranties | |
79 | * of merchantability, fitness for a particular purpose, or | 79 | * of merchantability, fitness for a particular purpose, or | |
80 | * non-infringement are disclaimed. In no event shall DIGITAL be | 80 | * non-infringement are disclaimed. In no event shall DIGITAL be | |
81 | * liable for any damages whatsoever, and in particular, DIGITAL | 81 | * liable for any damages whatsoever, and in particular, DIGITAL | |
82 | * shall not be liable for special, indirect, consequential, or | 82 | * shall not be liable for special, indirect, consequential, or | |
83 | * incidental damages or damages for lost profits, loss of | 83 | * incidental damages or damages for lost profits, loss of | |
84 | * revenue or loss of use, whether such damages arise in contract, | 84 | * revenue or loss of use, whether such damages arise in contract, | |
85 | * negligence, tort, under statute, in equity, at law or otherwise, | 85 | * negligence, tort, under statute, in equity, at law or otherwise, | |
86 | * even if advised of the possibility of such damage. | 86 | * even if advised of the possibility of such damage. | |
87 | */ | 87 | */ | |
88 | 88 | |||
89 | #include <sys/cdefs.h> | 89 | #include <sys/cdefs.h> | |
90 | 90 | |||
91 | #include <sys/param.h> | 91 | #include <sys/param.h> | |
92 | #include <sys/kernel.h> | 92 | #include <sys/kernel.h> | |
93 | #include <sys/systm.h> | 93 | #include <sys/systm.h> | |
94 | #include <sys/mbuf.h> | 94 | #include <sys/mbuf.h> | |
95 | #include <sys/syslog.h> | 95 | #include <sys/syslog.h> | |
96 | #include <sys/socket.h> | 96 | #include <sys/socket.h> | |
97 | #include <sys/device.h> | 97 | #include <sys/device.h> | |
98 | #include <sys/malloc.h> | 98 | #include <sys/malloc.h> | |
99 | #include <sys/ioctl.h> | 99 | #include <sys/ioctl.h> | |
100 | #include <sys/errno.h> | 100 | #include <sys/errno.h> | |
101 | 101 | |||
102 | #include <net/if.h> | 102 | #include <net/if.h> | |
103 | #include <net/if_ether.h> | 103 | #include <net/if_ether.h> | |
104 | #include <net/if_media.h> | 104 | #include <net/if_media.h> | |
105 | #include <net/bpf.h> | 105 | #include <net/bpf.h> | |
106 | 106 | |||
107 | #ifdef INET | 107 | #ifdef INET | |
108 | #include <netinet/in.h> | 108 | #include <netinet/in.h> | |
109 | #include <netinet/if_inarp.h> | 109 | #include <netinet/if_inarp.h> | |
110 | #endif | 110 | #endif | |
111 | 111 | |||
112 | #include <sys/bus.h> | 112 | #include <sys/bus.h> | |
113 | #include <sys/intr.h> | 113 | #include <sys/intr.h> | |
114 | 114 | |||
115 | #include <dev/ic/dm9000var.h> | 115 | #include <dev/ic/dm9000var.h> | |
116 | #include <dev/ic/dm9000reg.h> | 116 | #include <dev/ic/dm9000reg.h> | |
117 | 117 | |||
118 | #if 1 | 118 | #if 1 | |
119 | #undef DM9000_DEBUG | 119 | #undef DM9000_DEBUG | |
120 | #undef DM9000_TX_DEBUG | 120 | #undef DM9000_TX_DEBUG | |
121 | #undef DM9000_TX_DATA_DEBUG | 121 | #undef DM9000_TX_DATA_DEBUG | |
122 | #undef DM9000_RX_DEBUG | 122 | #undef DM9000_RX_DEBUG | |
123 | #undef DM9000_RX_DATA_DEBUG | 123 | #undef DM9000_RX_DATA_DEBUG | |
124 | #else | 124 | #else | |
125 | #define DM9000_DEBUG | 125 | #define DM9000_DEBUG | |
126 | #define DM9000_TX_DEBUG | 126 | #define DM9000_TX_DEBUG | |
127 | #define DM9000_TX_DATA_DEBUG | 127 | #define DM9000_TX_DATA_DEBUG | |
128 | #define DM9000_RX_DEBUG | 128 | #define DM9000_RX_DEBUG | |
129 | #define DM9000_RX_DATA_DEBUG | 129 | #define DM9000_RX_DATA_DEBUG | |
130 | #endif | 130 | #endif | |
131 | 131 | |||
132 | #ifdef DM9000_DEBUG | 132 | #ifdef DM9000_DEBUG | |
133 | #define DPRINTF(s) do {printf s; } while (/*CONSTCOND*/0) | 133 | #define DPRINTF(s) do {printf s; } while (/*CONSTCOND*/0) | |
134 | #else | 134 | #else | |
135 | #define DPRINTF(s) do {} while (/*CONSTCOND*/0) | 135 | #define DPRINTF(s) do {} while (/*CONSTCOND*/0) | |
136 | #endif | 136 | #endif | |
137 | 137 | |||
138 | #ifdef DM9000_TX_DEBUG | 138 | #ifdef DM9000_TX_DEBUG | |
139 | #define TX_DPRINTF(s) do {printf s; } while (/*CONSTCOND*/0) | 139 | #define TX_DPRINTF(s) do {printf s; } while (/*CONSTCOND*/0) | |
140 | #else | 140 | #else | |
141 | #define TX_DPRINTF(s) do {} while (/*CONSTCOND*/0) | 141 | #define TX_DPRINTF(s) do {} while (/*CONSTCOND*/0) | |
142 | #endif | 142 | #endif | |
143 | 143 | |||
144 | #ifdef DM9000_RX_DEBUG | 144 | #ifdef DM9000_RX_DEBUG | |
145 | #define RX_DPRINTF(s) do {printf s; } while (/*CONSTCOND*/0) | 145 | #define RX_DPRINTF(s) do {printf s; } while (/*CONSTCOND*/0) | |
146 | #else | 146 | #else | |
147 | #define RX_DPRINTF(s) do {} while (/*CONSTCOND*/0) | 147 | #define RX_DPRINTF(s) do {} while (/*CONSTCOND*/0) | |
148 | #endif | 148 | #endif | |
149 | 149 | |||
150 | #ifdef DM9000_RX_DATA_DEBUG | 150 | #ifdef DM9000_RX_DATA_DEBUG | |
151 | #define RX_DATA_DPRINTF(s) do {printf s; } while (/*CONSTCOND*/0) | 151 | #define RX_DATA_DPRINTF(s) do {printf s; } while (/*CONSTCOND*/0) | |
152 | #else | 152 | #else | |
153 | #define RX_DATA_DPRINTF(s) do {} while (/*CONSTCOND*/0) | 153 | #define RX_DATA_DPRINTF(s) do {} while (/*CONSTCOND*/0) | |
154 | #endif | 154 | #endif | |
155 | 155 | |||
156 | #ifdef DM9000_TX_DATA_DEBUG | 156 | #ifdef DM9000_TX_DATA_DEBUG | |
157 | #define TX_DATA_DPRINTF(s) do {printf s; } while (/*CONSTCOND*/0) | 157 | #define TX_DATA_DPRINTF(s) do {printf s; } while (/*CONSTCOND*/0) | |
158 | #else | 158 | #else | |
159 | #define TX_DATA_DPRINTF(s) do {} while (/*CONSTCOND*/0) | 159 | #define TX_DATA_DPRINTF(s) do {} while (/*CONSTCOND*/0) | |
160 | #endif | 160 | #endif | |
161 | 161 | |||
162 | /*** Internal PHY functions ***/ | 162 | /*** Internal PHY functions ***/ | |
163 | uint16_t dme_phy_read(struct dme_softc *, int ); | 163 | uint16_t dme_phy_read(struct dme_softc *, int ); | |
164 | void dme_phy_write(struct dme_softc *, int, uint16_t); | 164 | void dme_phy_write(struct dme_softc *, int, uint16_t); | |
165 | void dme_phy_init(struct dme_softc *); | 165 | void dme_phy_init(struct dme_softc *); | |
166 | void dme_phy_reset(struct dme_softc *); | 166 | void dme_phy_reset(struct dme_softc *); | |
167 | void dme_phy_update_media(struct dme_softc *); | 167 | void dme_phy_update_media(struct dme_softc *); | |
168 | void dme_phy_check_link(void *); | 168 | void dme_phy_check_link(void *); | |
169 | 169 | |||
170 | /*** Methods registered in struct ifnet ***/ | 170 | /*** Methods registered in struct ifnet ***/ | |
171 | void dme_start_output(struct ifnet *); | 171 | void dme_start_output(struct ifnet *); | |
172 | int dme_init(struct ifnet *); | 172 | int dme_init(struct ifnet *); | |
173 | int dme_ioctl(struct ifnet *, u_long, void *); | 173 | int dme_ioctl(struct ifnet *, u_long, void *); | |
174 | void dme_stop(struct ifnet *, int); | 174 | void dme_stop(struct ifnet *, int); | |
175 | 175 | |||
176 | int dme_mediachange(struct ifnet *); | 176 | int dme_mediachange(struct ifnet *); | |
177 | void dme_mediastatus(struct ifnet *, struct ifmediareq *); | 177 | void dme_mediastatus(struct ifnet *, struct ifmediareq *); | |
178 | 178 | |||
179 | /*** Internal methods ***/ | 179 | /*** Internal methods ***/ | |
180 | 180 | |||
181 | /* Prepare data to be transmitted (i.e. dequeue and load it into the DM9000) */ | 181 | /* Prepare data to be transmitted (i.e. dequeue and load it into the DM9000) */ | |
182 | void dme_prepare(struct dme_softc *, struct ifnet *); | 182 | void dme_prepare(struct dme_softc *, struct ifnet *); | |
183 | 183 | |||
184 | /* Transmit prepared data */ | 184 | /* Transmit prepared data */ | |
185 | void dme_transmit(struct dme_softc *); | 185 | void dme_transmit(struct dme_softc *); | |
186 | 186 | |||
187 | /* Receive data */ | 187 | /* Receive data */ | |
188 | void dme_receive(struct dme_softc *, struct ifnet *); | 188 | void dme_receive(struct dme_softc *, struct ifnet *); | |
189 | 189 | |||
190 | /* Software Initialize/Reset of the DM9000 */ | 190 | /* Software Initialize/Reset of the DM9000 */ | |
191 | void dme_reset(struct dme_softc *); | 191 | void dme_reset(struct dme_softc *); | |
192 | 192 | |||
193 | /* Configure multicast filter */ | 193 | /* Configure multicast filter */ | |
194 | void dme_set_addr_filter(struct dme_softc *); | 194 | void dme_set_addr_filter(struct dme_softc *); | |
195 | 195 | |||
196 | /* Set media */ | 196 | /* Set media */ | |
197 | int dme_set_media(struct dme_softc *, int ); | 197 | int dme_set_media(struct dme_softc *, int ); | |
198 | 198 | |||
199 | /* Read/write packet data from/to DM9000 IC in various transfer sizes */ | 199 | /* Read/write packet data from/to DM9000 IC in various transfer sizes */ | |
200 | int dme_pkt_read_2(struct dme_softc *, struct ifnet *, struct mbuf **); | 200 | int dme_pkt_read_2(struct dme_softc *, struct ifnet *, struct mbuf **); | |
201 | int dme_pkt_write_2(struct dme_softc *, struct mbuf *); | 201 | int dme_pkt_write_2(struct dme_softc *, struct mbuf *); | |
202 | int dme_pkt_read_1(struct dme_softc *, struct ifnet *, struct mbuf **); | 202 | int dme_pkt_read_1(struct dme_softc *, struct ifnet *, struct mbuf **); | |
203 | int dme_pkt_write_1(struct dme_softc *, struct mbuf *); | 203 | int dme_pkt_write_1(struct dme_softc *, struct mbuf *); | |
204 | /* TODO: Implement 32 bit read/write functions */ | 204 | /* TODO: Implement 32 bit read/write functions */ | |
205 | 205 | |||
206 | uint16_t | 206 | uint16_t | |
207 | dme_phy_read(struct dme_softc *sc, int reg) | 207 | dme_phy_read(struct dme_softc *sc, int reg) | |
208 | { | 208 | { | |
209 | uint16_t val; | 209 | uint16_t val; | |
210 | /* Select Register to read*/ | 210 | /* Select Register to read*/ | |
211 | dme_write(sc, DM9000_EPAR, DM9000_EPAR_INT_PHY + | 211 | dme_write(sc, DM9000_EPAR, DM9000_EPAR_INT_PHY + | |
212 | (reg & DM9000_EPAR_EROA_MASK)); | 212 | (reg & DM9000_EPAR_EROA_MASK)); | |
213 | /* Select read operation (DM9000_EPCR_ERPRR) from the PHY */ | 213 | /* Select read operation (DM9000_EPCR_ERPRR) from the PHY */ | |
214 | dme_write(sc, DM9000_EPCR, DM9000_EPCR_ERPRR + DM9000_EPCR_EPOS_PHY); | 214 | dme_write(sc, DM9000_EPCR, DM9000_EPCR_ERPRR + DM9000_EPCR_EPOS_PHY); | |
215 | 215 | |||
216 | /* Wait until access to PHY has completed */ | 216 | /* Wait until access to PHY has completed */ | |
217 | while (dme_read(sc, DM9000_EPCR) & DM9000_EPCR_ERRE) | 217 | while (dme_read(sc, DM9000_EPCR) & DM9000_EPCR_ERRE) | |
218 | ; | 218 | ; | |
219 | 219 | |||
220 | /* Reset ERPRR-bit */ | 220 | /* Reset ERPRR-bit */ | |
221 | dme_write(sc, DM9000_EPCR, DM9000_EPCR_EPOS_PHY); | 221 | dme_write(sc, DM9000_EPCR, DM9000_EPCR_EPOS_PHY); | |
222 | 222 | |||
223 | val = dme_read(sc, DM9000_EPDRL); | 223 | val = dme_read(sc, DM9000_EPDRL); | |
224 | val += dme_read(sc, DM9000_EPDRH) << 8; | 224 | val += dme_read(sc, DM9000_EPDRH) << 8; | |
225 | 225 | |||
226 | return val; | 226 | return val; | |
227 | } | 227 | } | |
228 | 228 | |||
229 | void | 229 | void | |
230 | dme_phy_write(struct dme_softc *sc, int reg, uint16_t value) | 230 | dme_phy_write(struct dme_softc *sc, int reg, uint16_t value) | |
231 | { | 231 | { | |
232 | /* Select Register to write*/ | 232 | /* Select Register to write*/ | |
233 | dme_write(sc, DM9000_EPAR, DM9000_EPAR_INT_PHY + | 233 | dme_write(sc, DM9000_EPAR, DM9000_EPAR_INT_PHY + | |
234 | (reg & DM9000_EPAR_EROA_MASK)); | 234 | (reg & DM9000_EPAR_EROA_MASK)); | |
235 | 235 | |||
236 | /* Write data to the two data registers */ | 236 | /* Write data to the two data registers */ | |
237 | dme_write(sc, DM9000_EPDRL, value & 0xFF); | 237 | dme_write(sc, DM9000_EPDRL, value & 0xFF); | |
238 | dme_write(sc, DM9000_EPDRH, (value >> 8) & 0xFF); | 238 | dme_write(sc, DM9000_EPDRH, (value >> 8) & 0xFF); | |
239 | 239 | |||
240 | /* Select write operation (DM9000_EPCR_ERPRW) from the PHY */ | 240 | /* Select write operation (DM9000_EPCR_ERPRW) from the PHY */ | |
241 | dme_write(sc, DM9000_EPCR, DM9000_EPCR_ERPRW + DM9000_EPCR_EPOS_PHY); | 241 | dme_write(sc, DM9000_EPCR, DM9000_EPCR_ERPRW + DM9000_EPCR_EPOS_PHY); | |
242 | 242 | |||
243 | /* Wait until access to PHY has completed */ | 243 | /* Wait until access to PHY has completed */ | |
244 | while (dme_read(sc, DM9000_EPCR) & DM9000_EPCR_ERRE) | 244 | while (dme_read(sc, DM9000_EPCR) & DM9000_EPCR_ERRE) | |
245 | ; | 245 | ; | |
246 | 246 | |||
247 | /* Reset ERPRR-bit */ | 247 | /* Reset ERPRR-bit */ | |
248 | dme_write(sc, DM9000_EPCR, DM9000_EPCR_EPOS_PHY); | 248 | dme_write(sc, DM9000_EPCR, DM9000_EPCR_EPOS_PHY); | |
249 | } | 249 | } | |
250 | 250 | |||
251 | void | 251 | void | |
252 | dme_phy_init(struct dme_softc *sc) | 252 | dme_phy_init(struct dme_softc *sc) | |
253 | { | 253 | { | |
254 | u_int ifm_media = sc->sc_media.ifm_media; | 254 | u_int ifm_media = sc->sc_media.ifm_media; | |
255 | uint32_t bmcr, anar; | 255 | uint32_t bmcr, anar; | |
256 | 256 | |||
257 | bmcr = dme_phy_read(sc, DM9000_PHY_BMCR); | 257 | bmcr = dme_phy_read(sc, DM9000_PHY_BMCR); | |
258 | anar = dme_phy_read(sc, DM9000_PHY_ANAR); | 258 | anar = dme_phy_read(sc, DM9000_PHY_ANAR); | |
259 | 259 | |||
260 | anar = anar & ~DM9000_PHY_ANAR_10_HDX | 260 | anar = anar & ~DM9000_PHY_ANAR_10_HDX | |
261 | & ~DM9000_PHY_ANAR_10_FDX | 261 | & ~DM9000_PHY_ANAR_10_FDX | |
262 | & ~DM9000_PHY_ANAR_TX_HDX | 262 | & ~DM9000_PHY_ANAR_TX_HDX | |
263 | & ~DM9000_PHY_ANAR_TX_FDX; | 263 | & ~DM9000_PHY_ANAR_TX_FDX; | |
264 | 264 | |||
265 | switch (IFM_SUBTYPE(ifm_media)) { | 265 | switch (IFM_SUBTYPE(ifm_media)) { | |
266 | case IFM_AUTO: | 266 | case IFM_AUTO: | |
267 | bmcr |= DM9000_PHY_BMCR_AUTO_NEG_EN; | 267 | bmcr |= DM9000_PHY_BMCR_AUTO_NEG_EN; | |
268 | anar |= DM9000_PHY_ANAR_10_HDX | | 268 | anar |= DM9000_PHY_ANAR_10_HDX | | |
269 | DM9000_PHY_ANAR_10_FDX | | 269 | DM9000_PHY_ANAR_10_FDX | | |
270 | DM9000_PHY_ANAR_TX_HDX | | 270 | DM9000_PHY_ANAR_TX_HDX | | |
271 | DM9000_PHY_ANAR_TX_FDX; | 271 | DM9000_PHY_ANAR_TX_FDX; | |
272 | break; | 272 | break; | |
273 | case IFM_10_T: | 273 | case IFM_10_T: | |
274 | //bmcr &= ~DM9000_PHY_BMCR_AUTO_NEG_EN; | 274 | //bmcr &= ~DM9000_PHY_BMCR_AUTO_NEG_EN; | |
275 | bmcr &= ~DM9000_PHY_BMCR_SPEED_SELECT; | 275 | bmcr &= ~DM9000_PHY_BMCR_SPEED_SELECT; | |
276 | if (ifm_media & IFM_FDX) | 276 | if (ifm_media & IFM_FDX) | |
277 | anar |= DM9000_PHY_ANAR_10_FDX; | 277 | anar |= DM9000_PHY_ANAR_10_FDX; | |
278 | else | 278 | else | |
279 | anar |= DM9000_PHY_ANAR_10_HDX; | 279 | anar |= DM9000_PHY_ANAR_10_HDX; | |
280 | break; | 280 | break; | |
281 | case IFM_100_TX: | 281 | case IFM_100_TX: | |
282 | //bmcr &= ~DM9000_PHY_BMCR_AUTO_NEG_EN; | 282 | //bmcr &= ~DM9000_PHY_BMCR_AUTO_NEG_EN; | |
283 | bmcr |= DM9000_PHY_BMCR_SPEED_SELECT; | 283 | bmcr |= DM9000_PHY_BMCR_SPEED_SELECT; | |
284 | if (ifm_media & IFM_FDX) | 284 | if (ifm_media & IFM_FDX) | |
285 | anar |= DM9000_PHY_ANAR_TX_FDX; | 285 | anar |= DM9000_PHY_ANAR_TX_FDX; | |
286 | else | 286 | else | |
287 | anar |= DM9000_PHY_ANAR_TX_HDX; | 287 | anar |= DM9000_PHY_ANAR_TX_HDX; | |
288 | 288 | |||
289 | break; | 289 | break; | |
290 | } | 290 | } | |
291 | 291 | |||
292 | if (ifm_media & IFM_FDX) | 292 | if (ifm_media & IFM_FDX) | |
293 | bmcr |= DM9000_PHY_BMCR_DUPLEX_MODE; | 293 | bmcr |= DM9000_PHY_BMCR_DUPLEX_MODE; | |
294 | else | 294 | else | |
295 | bmcr &= ~DM9000_PHY_BMCR_DUPLEX_MODE; | 295 | bmcr &= ~DM9000_PHY_BMCR_DUPLEX_MODE; | |
296 | 296 | |||
297 | dme_phy_write(sc, DM9000_PHY_BMCR, bmcr); | 297 | dme_phy_write(sc, DM9000_PHY_BMCR, bmcr); | |
298 | dme_phy_write(sc, DM9000_PHY_ANAR, anar); | 298 | dme_phy_write(sc, DM9000_PHY_ANAR, anar); | |
299 | } | 299 | } | |
300 | 300 | |||
301 | void | 301 | void | |
302 | dme_phy_reset(struct dme_softc *sc) | 302 | dme_phy_reset(struct dme_softc *sc) | |
303 | { | 303 | { | |
304 | uint32_t reg; | 304 | uint32_t reg; | |
305 | 305 | |||
306 | /* PHY Reset */ | 306 | /* PHY Reset */ | |
307 | dme_phy_write(sc, DM9000_PHY_BMCR, DM9000_PHY_BMCR_RESET); | 307 | dme_phy_write(sc, DM9000_PHY_BMCR, DM9000_PHY_BMCR_RESET); | |
308 | 308 | |||
309 | reg = dme_read(sc, DM9000_GPCR); | 309 | reg = dme_read(sc, DM9000_GPCR); | |
310 | dme_write(sc, DM9000_GPCR, reg & ~DM9000_GPCR_GPIO0_OUT); | 310 | dme_write(sc, DM9000_GPCR, reg & ~DM9000_GPCR_GPIO0_OUT); | |
311 | reg = dme_read(sc, DM9000_GPR); | 311 | reg = dme_read(sc, DM9000_GPR); | |
312 | dme_write(sc, DM9000_GPR, reg | DM9000_GPR_PHY_PWROFF); | 312 | dme_write(sc, DM9000_GPR, reg | DM9000_GPR_PHY_PWROFF); | |
313 | 313 | |||
314 | dme_phy_init(sc); | 314 | dme_phy_init(sc); | |
315 | 315 | |||
316 | reg = dme_read(sc, DM9000_GPR); | 316 | reg = dme_read(sc, DM9000_GPR); | |
317 | dme_write(sc, DM9000_GPR, reg & ~DM9000_GPR_PHY_PWROFF); | 317 | dme_write(sc, DM9000_GPR, reg & ~DM9000_GPR_PHY_PWROFF); | |
318 | reg = dme_read(sc, DM9000_GPCR); | 318 | reg = dme_read(sc, DM9000_GPCR); | |
319 | dme_write(sc, DM9000_GPCR, reg | DM9000_GPCR_GPIO0_OUT); | 319 | dme_write(sc, DM9000_GPCR, reg | DM9000_GPCR_GPIO0_OUT); | |
320 | 320 | |||
321 | dme_phy_update_media(sc); | 321 | dme_phy_update_media(sc); | |
322 | } | 322 | } | |
323 | 323 | |||
324 | void | 324 | void | |
325 | dme_phy_update_media(struct dme_softc *sc) | 325 | dme_phy_update_media(struct dme_softc *sc) | |
326 | { | 326 | { | |
327 | u_int ifm_media = sc->sc_media.ifm_media; | 327 | u_int ifm_media = sc->sc_media.ifm_media; | |
328 | uint32_t reg; | 328 | uint32_t reg; | |
329 | 329 | |||
330 | if (IFM_SUBTYPE(ifm_media) == IFM_AUTO) { | 330 | if (IFM_SUBTYPE(ifm_media) == IFM_AUTO) { | |
331 | /* If auto-negotiation is used, ensures that it is completed | 331 | /* If auto-negotiation is used, ensures that it is completed | |
332 | before trying to extract any media information. */ | 332 | before trying to extract any media information. */ | |
333 | reg = dme_phy_read(sc, DM9000_PHY_BMSR); | 333 | reg = dme_phy_read(sc, DM9000_PHY_BMSR); | |
334 | if ((reg & DM9000_PHY_BMSR_AUTO_NEG_AB) == 0) { | 334 | if ((reg & DM9000_PHY_BMSR_AUTO_NEG_AB) == 0) { | |
335 | /* Auto-negotation not possible, therefore there is no | 335 | /* Auto-negotation not possible, therefore there is no | |
336 | reason to try obtain any media information. */ | 336 | reason to try obtain any media information. */ | |
337 | return; | 337 | return; | |
338 | } | 338 | } | |
339 | 339 | |||
340 | /* Then loop until the negotiation is completed. */ | 340 | /* Then loop until the negotiation is completed. */ | |
341 | while ((reg & DM9000_PHY_BMSR_AUTO_NEG_COM) == 0) { | 341 | while ((reg & DM9000_PHY_BMSR_AUTO_NEG_COM) == 0) { | |
342 | /* TODO: Bail out after a finite number of attempts | 342 | /* TODO: Bail out after a finite number of attempts | |
343 | in case something goes wrong. */ | 343 | in case something goes wrong. */ | |
344 | preempt(); | 344 | preempt(); | |
345 | reg = dme_phy_read(sc, DM9000_PHY_BMSR); | 345 | reg = dme_phy_read(sc, DM9000_PHY_BMSR); | |
346 | } | 346 | } | |
347 | } | 347 | } | |
348 | 348 | |||
349 | 349 | |||
350 | sc->sc_media_active = IFM_ETHER; | 350 | sc->sc_media_active = IFM_ETHER; | |
351 | reg = dme_phy_read(sc, DM9000_PHY_BMCR); | 351 | reg = dme_phy_read(sc, DM9000_PHY_BMCR); | |
352 | 352 | |||
353 | if (reg & DM9000_PHY_BMCR_SPEED_SELECT) | 353 | if (reg & DM9000_PHY_BMCR_SPEED_SELECT) | |
354 | sc->sc_media_active |= IFM_100_TX; | 354 | sc->sc_media_active |= IFM_100_TX; | |
355 | else | 355 | else | |
356 | sc->sc_media_active |= IFM_10_T; | 356 | sc->sc_media_active |= IFM_10_T; | |
357 | 357 | |||
358 | if (reg & DM9000_PHY_BMCR_DUPLEX_MODE) | 358 | if (reg & DM9000_PHY_BMCR_DUPLEX_MODE) | |
359 | sc->sc_media_active |= IFM_FDX; | 359 | sc->sc_media_active |= IFM_FDX; | |
360 | } | 360 | } | |
361 | 361 | |||
362 | void | 362 | void | |
363 | dme_phy_check_link(void *arg) | 363 | dme_phy_check_link(void *arg) | |
364 | { | 364 | { | |
365 | struct dme_softc *sc = arg; | 365 | struct dme_softc *sc = arg; | |
366 | uint32_t reg; | 366 | uint32_t reg; | |
367 | int s; | 367 | int s; | |
368 | 368 | |||
369 | s = splnet(); | 369 | s = splnet(); | |
370 | 370 | |||
371 | reg = dme_read(sc, DM9000_NSR) & DM9000_NSR_LINKST; | 371 | reg = dme_read(sc, DM9000_NSR) & DM9000_NSR_LINKST; | |
372 | 372 | |||
373 | if (reg) | 373 | if (reg) | |
374 | reg = IFM_ETHER | IFM_AVALID | IFM_ACTIVE; | 374 | reg = IFM_ETHER | IFM_AVALID | IFM_ACTIVE; | |
375 | else { | 375 | else { | |
376 | reg = IFM_ETHER | IFM_AVALID; | 376 | reg = IFM_ETHER | IFM_AVALID; | |
377 | sc->sc_media_active = IFM_NONE; | 377 | sc->sc_media_active = IFM_NONE; | |
378 | } | 378 | } | |
379 | 379 | |||
380 | if ((sc->sc_media_status != reg) && (reg & IFM_ACTIVE)) | 380 | if ((sc->sc_media_status != reg) && (reg & IFM_ACTIVE)) | |
381 | dme_phy_reset(sc); | 381 | dme_phy_reset(sc); | |
382 | 382 | |||
383 | sc->sc_media_status = reg; | 383 | sc->sc_media_status = reg; | |
384 | 384 | |||
385 | callout_schedule(&sc->sc_link_callout, mstohz(2000)); | 385 | callout_schedule(&sc->sc_link_callout, mstohz(2000)); | |
386 | splx(s); | 386 | splx(s); | |
387 | } | 387 | } | |
388 | 388 | |||
389 | int | 389 | int | |
390 | dme_set_media(struct dme_softc *sc, int media) | 390 | dme_set_media(struct dme_softc *sc, int media) | |
391 | { | 391 | { | |
392 | int s; | 392 | int s; | |
393 | 393 | |||
394 | s = splnet(); | 394 | s = splnet(); | |
395 | sc->sc_media.ifm_media = media; | 395 | sc->sc_media.ifm_media = media; | |
396 | dme_phy_reset(sc); | 396 | dme_phy_reset(sc); | |
397 | 397 | |||
398 | splx(s); | 398 | splx(s); | |
399 | 399 | |||
400 | return 0; | 400 | return 0; | |
401 | } | 401 | } | |
402 | 402 | |||
403 | int | 403 | int | |
404 | dme_attach(struct dme_softc *sc, const uint8_t *enaddr) | 404 | dme_attach(struct dme_softc *sc, const uint8_t *enaddr) | |
405 | { | 405 | { | |
406 | struct ifnet *ifp = &sc->sc_ethercom.ec_if; | 406 | struct ifnet *ifp = &sc->sc_ethercom.ec_if; | |
407 | uint8_t b[2]; | 407 | uint8_t b[2]; | |
408 | uint16_t io_mode; | 408 | uint16_t io_mode; | |
409 | 409 | |||
410 | dme_read_c(sc, DM9000_VID0, b, 2); | 410 | dme_read_c(sc, DM9000_VID0, b, 2); | |
411 | #if BYTE_ORDER == BIG_ENDIAN | 411 | #if BYTE_ORDER == BIG_ENDIAN | |
412 | sc->sc_vendor_id = (b[0] << 8) | b[1]; | 412 | sc->sc_vendor_id = (b[0] << 8) | b[1]; | |
413 | #else | 413 | #else | |
414 | sc->sc_vendor_id = b[0] | (b[1] << 8); | 414 | sc->sc_vendor_id = b[0] | (b[1] << 8); | |
415 | #endif | 415 | #endif | |
416 | dme_read_c(sc, DM9000_PID0, b, 2); | 416 | dme_read_c(sc, DM9000_PID0, b, 2); | |
417 | #if BYTE_ORDER == BIG_ENDIAN | 417 | #if BYTE_ORDER == BIG_ENDIAN | |
418 | sc->sc_product_id = (b[0] << 8) | b[1]; | 418 | sc->sc_product_id = (b[0] << 8) | b[1]; | |
419 | #else | 419 | #else | |
420 | sc->sc_product_id = b[0] | (b[1] << 8); | 420 | sc->sc_product_id = b[0] | (b[1] << 8); | |
421 | #endif | 421 | #endif | |
422 | /* TODO: Check the vendor ID as well */ | 422 | /* TODO: Check the vendor ID as well */ | |
423 | if (sc->sc_product_id != 0x9000) { | 423 | if (sc->sc_product_id != 0x9000) { | |
424 | panic("dme_attach: product id mismatch (0x%hx != 0x9000)", | 424 | panic("dme_attach: product id mismatch (0x%hx != 0x9000)", | |
425 | sc->sc_product_id); | 425 | sc->sc_product_id); | |
426 | } | 426 | } | |
427 | 427 | |||
428 | /* Initialize ifnet structure. */ | 428 | /* Initialize ifnet structure. */ | |
429 | strlcpy(ifp->if_xname, device_xname(sc->sc_dev), IFNAMSIZ); | 429 | strlcpy(ifp->if_xname, device_xname(sc->sc_dev), IFNAMSIZ); | |
430 | ifp->if_softc = sc; | 430 | ifp->if_softc = sc; | |
431 | ifp->if_start = dme_start_output; | 431 | ifp->if_start = dme_start_output; | |
432 | ifp->if_init = dme_init; | 432 | ifp->if_init = dme_init; | |
433 | ifp->if_ioctl = dme_ioctl; | 433 | ifp->if_ioctl = dme_ioctl; | |
434 | ifp->if_stop = dme_stop; | 434 | ifp->if_stop = dme_stop; | |
435 | ifp->if_watchdog = NULL; /* no watchdog at this stage */ | 435 | ifp->if_watchdog = NULL; /* no watchdog at this stage */ | |
436 | ifp->if_flags = IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST; | 436 | ifp->if_flags = IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST; | |
437 | IFQ_SET_READY(&ifp->if_snd); | 437 | IFQ_SET_READY(&ifp->if_snd); | |
438 | 438 | |||
439 | /* Initialize ifmedia structures. */ | 439 | /* Initialize ifmedia structures. */ | |
440 | sc->sc_ethercom.ec_ifmedia = &sc->sc_media; | 440 | sc->sc_ethercom.ec_ifmedia = &sc->sc_media; | |
441 | ifmedia_init(&sc->sc_media, 0, dme_mediachange, dme_mediastatus); | 441 | ifmedia_init(&sc->sc_media, 0, dme_mediachange, dme_mediastatus); | |
442 | ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_AUTO, 0, NULL); | 442 | ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_AUTO, 0, NULL); | |
443 | ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_10_T | IFM_FDX, 0, NULL); | 443 | ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_10_T | IFM_FDX, 0, NULL); | |
444 | ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_10_T, 0, NULL); | 444 | ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_10_T, 0, NULL); | |
445 | ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_100_TX | IFM_FDX, 0, NULL); | 445 | ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_100_TX | IFM_FDX, 0, NULL); | |
446 | ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_100_TX, 0, NULL); | 446 | ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_100_TX, 0, NULL); | |
447 | 447 | |||
448 | ifmedia_set(&sc->sc_media, IFM_ETHER | IFM_AUTO); | 448 | ifmedia_set(&sc->sc_media, IFM_ETHER | IFM_AUTO); | |
449 | 449 | |||
450 | if (enaddr != NULL) | 450 | if (enaddr != NULL) | |
451 | memcpy(sc->sc_enaddr, enaddr, sizeof(sc->sc_enaddr)); | 451 | memcpy(sc->sc_enaddr, enaddr, sizeof(sc->sc_enaddr)); | |
452 | /* TODO: Support an EEPROM attached to the DM9000 chip */ | 452 | /* TODO: Support an EEPROM attached to the DM9000 chip */ | |
453 | 453 | |||
454 | callout_init(&sc->sc_link_callout, 0); | 454 | callout_init(&sc->sc_link_callout, 0); | |
455 | callout_setfunc(&sc->sc_link_callout, dme_phy_check_link, sc); | 455 | callout_setfunc(&sc->sc_link_callout, dme_phy_check_link, sc); | |
456 | 456 | |||
457 | sc->sc_media_status = 0; | 457 | sc->sc_media_status = 0; | |
458 | 458 | |||
459 | /* Configure DM9000 with the MAC address */ | 459 | /* Configure DM9000 with the MAC address */ | |
460 | dme_write_c(sc, DM9000_PAB0, sc->sc_enaddr, 6); | 460 | dme_write_c(sc, DM9000_PAB0, sc->sc_enaddr, 6); | |
461 | 461 | |||
462 | #ifdef DM9000_DEBUG | 462 | #ifdef DM9000_DEBUG | |
463 | { | 463 | { | |
464 | uint8_t macAddr[6]; | 464 | uint8_t macAddr[6]; | |
465 | dme_read_c(sc, DM9000_PAB0, macAddr, 6); | 465 | dme_read_c(sc, DM9000_PAB0, macAddr, 6); | |
466 | printf("DM9000 configured with MAC address: "); | 466 | printf("DM9000 configured with MAC address: "); | |
467 | for (int i = 0; i < 6; i++) | 467 | for (int i = 0; i < 6; i++) | |
468 | printf("%02X:", macAddr[i]); | 468 | printf("%02X:", macAddr[i]); | |
469 | printf("\n"); | 469 | printf("\n"); | |
470 | } | 470 | } | |
471 | #endif | 471 | #endif | |
472 | 472 | |||
473 | if_attach(ifp); | 473 | if_attach(ifp); | |
474 | ether_ifattach(ifp, sc->sc_enaddr); | 474 | ether_ifattach(ifp, sc->sc_enaddr); | |
475 | 475 | |||
476 | #ifdef DM9000_DEBUG | 476 | #ifdef DM9000_DEBUG | |
477 | { | 477 | { | |
478 | uint8_t network_state; | 478 | uint8_t network_state; | |
479 | network_state = dme_read(sc, DM9000_NSR); | 479 | network_state = dme_read(sc, DM9000_NSR); | |
480 | printf("DM9000 Link status: "); | 480 | printf("DM9000 Link status: "); | |
481 | if (network_state & DM9000_NSR_LINKST) { | 481 | if (network_state & DM9000_NSR_LINKST) { | |
482 | if (network_state & DM9000_NSR_SPEED) | 482 | if (network_state & DM9000_NSR_SPEED) | |
483 | printf("10Mbps"); | 483 | printf("10Mbps"); | |
484 | else | 484 | else | |
485 | printf("100Mbps"); | 485 | printf("100Mbps"); | |
486 | } else | 486 | } else | |
487 | printf("Down"); | 487 | printf("Down"); | |
488 | printf("\n"); | 488 | printf("\n"); | |
489 | } | 489 | } | |
490 | #endif | 490 | #endif | |
491 | 491 | |||
492 | io_mode = (dme_read(sc, DM9000_ISR) & | 492 | io_mode = (dme_read(sc, DM9000_ISR) & | |
493 | DM9000_IOMODE_MASK) >> DM9000_IOMODE_SHIFT; | 493 | DM9000_IOMODE_MASK) >> DM9000_IOMODE_SHIFT; | |
494 | 494 | |||
495 | DPRINTF(("DM9000 Operation Mode: ")); | 495 | DPRINTF(("DM9000 Operation Mode: ")); | |
496 | switch (io_mode) { | 496 | switch (io_mode) { | |
497 | case DM9000_MODE_16BIT: | 497 | case DM9000_MODE_16BIT: | |
498 | DPRINTF(("16-bit mode")); | 498 | DPRINTF(("16-bit mode")); | |
499 | sc->sc_data_width = 2; | 499 | sc->sc_data_width = 2; | |
500 | sc->sc_pkt_write = dme_pkt_write_2; | 500 | sc->sc_pkt_write = dme_pkt_write_2; | |
501 | sc->sc_pkt_read = dme_pkt_read_2; | 501 | sc->sc_pkt_read = dme_pkt_read_2; | |
502 | break; | 502 | break; | |
503 | case DM9000_MODE_32BIT: | 503 | case DM9000_MODE_32BIT: | |
504 | DPRINTF(("32-bit mode")); | 504 | DPRINTF(("32-bit mode")); | |
505 | sc->sc_data_width = 4; | 505 | sc->sc_data_width = 4; | |
506 | panic("32bit mode is unsupported\n"); | 506 | panic("32bit mode is unsupported\n"); | |
507 | break; | 507 | break; | |
508 | case DM9000_MODE_8BIT: | 508 | case DM9000_MODE_8BIT: | |
509 | DPRINTF(("8-bit mode")); | 509 | DPRINTF(("8-bit mode")); | |
510 | sc->sc_data_width = 1; | 510 | sc->sc_data_width = 1; | |
511 | sc->sc_pkt_write = dme_pkt_write_1; | 511 | sc->sc_pkt_write = dme_pkt_write_1; | |
512 | sc->sc_pkt_read = dme_pkt_read_1; | 512 | sc->sc_pkt_read = dme_pkt_read_1; | |
513 | break; | 513 | break; | |
514 | default: | 514 | default: | |
515 | DPRINTF(("Invalid mode")); | 515 | DPRINTF(("Invalid mode")); | |
516 | break; | 516 | break; | |
517 | } | 517 | } | |
518 | DPRINTF(("\n")); | 518 | DPRINTF(("\n")); | |
519 | 519 | |||
520 | callout_schedule(&sc->sc_link_callout, mstohz(2000)); | 520 | callout_schedule(&sc->sc_link_callout, mstohz(2000)); | |
521 | 521 | |||
522 | return 0; | 522 | return 0; | |
523 | } | 523 | } | |
524 | 524 | |||
525 | int dme_intr(void *arg) | 525 | int dme_intr(void *arg) | |
526 | { | 526 | { | |
527 | struct dme_softc *sc = arg; | 527 | struct dme_softc *sc = arg; | |
528 | struct ifnet *ifp = &sc->sc_ethercom.ec_if; | 528 | struct ifnet *ifp = &sc->sc_ethercom.ec_if; | |
529 | uint8_t status; | 529 | uint8_t status; | |
530 | 530 | |||
531 | 531 | |||
532 | DPRINTF(("dme_intr: Begin\n")); | 532 | DPRINTF(("dme_intr: Begin\n")); | |
533 | 533 | |||
534 | /* Disable interrupts */ | 534 | /* Disable interrupts */ | |
535 | dme_write(sc, DM9000_IMR, DM9000_IMR_PAR ); | 535 | dme_write(sc, DM9000_IMR, DM9000_IMR_PAR ); | |
536 | 536 | |||
537 | status = dme_read(sc, DM9000_ISR); | 537 | status = dme_read(sc, DM9000_ISR); | |
538 | dme_write(sc, DM9000_ISR, status); | 538 | dme_write(sc, DM9000_ISR, status); | |
539 | 539 | |||
540 | if (status & DM9000_ISR_PRS) { | 540 | if (status & DM9000_ISR_PRS) { | |
541 | if (ifp->if_flags & IFF_RUNNING ) | 541 | if (ifp->if_flags & IFF_RUNNING ) | |
542 | dme_receive(sc, ifp); | 542 | dme_receive(sc, ifp); | |
543 | } | 543 | } | |
544 | if (status & DM9000_ISR_PTS) { | 544 | if (status & DM9000_ISR_PTS) { | |
545 | uint8_t nsr; | 545 | uint8_t nsr; | |
546 | uint8_t tx_status = 0x01; /* Initialize to an error value */ | 546 | uint8_t tx_status = 0x01; /* Initialize to an error value */ | |
547 | 547 | |||
548 | /* A packet has been transmitted */ | 548 | /* A packet has been transmitted */ | |
549 | sc->txbusy = 0; | 549 | sc->txbusy = 0; | |
550 | 550 | |||
551 | nsr = dme_read(sc, DM9000_NSR); | 551 | nsr = dme_read(sc, DM9000_NSR); | |
552 | 552 | |||
553 | if (nsr & DM9000_NSR_TX1END) { | 553 | if (nsr & DM9000_NSR_TX1END) { | |
554 | tx_status = dme_read(sc, DM9000_TSR1); | 554 | tx_status = dme_read(sc, DM9000_TSR1); | |
555 | TX_DPRINTF(("dme_intr: Sent using channel 0\n")); | 555 | TX_DPRINTF(("dme_intr: Sent using channel 0\n")); | |
556 | } else if (nsr & DM9000_NSR_TX2END) { | 556 | } else if (nsr & DM9000_NSR_TX2END) { | |
557 | tx_status = dme_read(sc, DM9000_TSR2); | 557 | tx_status = dme_read(sc, DM9000_TSR2); | |
558 | TX_DPRINTF(("dme_intr: Sent using channel 1\n")); | 558 | TX_DPRINTF(("dme_intr: Sent using channel 1\n")); | |
559 | } | 559 | } | |
560 | 560 | |||
561 | if (tx_status == 0x0) { | 561 | if (tx_status == 0x0) { | |
562 | /* Frame successfully sent */ | 562 | /* Frame successfully sent */ | |
563 | ifp->if_opackets++; | 563 | if_statinc(ifp, if_opackets); | |
564 | } else { | 564 | } else { | |
565 | ifp->if_oerrors++; | 565 | if_statinc(ifp, if_oerrors); | |
566 | } | 566 | } | |
567 | 567 | |||
568 | /* If we have nothing ready to transmit, prepare something */ | 568 | /* If we have nothing ready to transmit, prepare something */ | |
569 | if (!sc->txready) | 569 | if (!sc->txready) | |
570 | dme_prepare(sc, ifp); | 570 | dme_prepare(sc, ifp); | |
571 | 571 | |||
572 | if (sc->txready) | 572 | if (sc->txready) | |
573 | dme_transmit(sc); | 573 | dme_transmit(sc); | |
574 | 574 | |||
575 | /* Prepare the next frame */ | 575 | /* Prepare the next frame */ | |
576 | dme_prepare(sc, ifp); | 576 | dme_prepare(sc, ifp); | |
577 | 577 | |||
578 | } | 578 | } | |
579 | #ifdef notyet | 579 | #ifdef notyet | |
580 | if (status & DM9000_ISR_LNKCHNG) { | 580 | if (status & DM9000_ISR_LNKCHNG) { | |
581 | } | 581 | } | |
582 | #endif | 582 | #endif | |
583 | 583 | |||
584 | /* Enable interrupts again */ | 584 | /* Enable interrupts again */ | |
585 | dme_write(sc, DM9000_IMR, | 585 | dme_write(sc, DM9000_IMR, | |
586 | DM9000_IMR_PAR | DM9000_IMR_PRM | DM9000_IMR_PTM); | 586 | DM9000_IMR_PAR | DM9000_IMR_PRM | DM9000_IMR_PTM); | |
587 | 587 | |||
588 | DPRINTF(("dme_intr: End\n")); | 588 | DPRINTF(("dme_intr: End\n")); | |
589 | 589 | |||
590 | return 1; | 590 | return 1; | |
591 | } | 591 | } | |
592 | 592 | |||
593 | void | 593 | void | |
594 | dme_start_output(struct ifnet *ifp) | 594 | dme_start_output(struct ifnet *ifp) | |
595 | { | 595 | { | |
596 | struct dme_softc *sc; | 596 | struct dme_softc *sc; | |
597 | 597 | |||
598 | sc = ifp->if_softc; | 598 | sc = ifp->if_softc; | |
599 | 599 | |||
600 | DPRINTF(("dme_start_output: Begin\n")); | 600 | DPRINTF(("dme_start_output: Begin\n")); | |
601 | 601 | |||
602 | if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING) { | 602 | if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING) { | |
603 | printf("No output\n"); | 603 | printf("No output\n"); | |
604 | return; | 604 | return; | |
605 | } | 605 | } | |
606 | 606 | |||
607 | if (sc->txbusy && sc->txready) | 607 | if (sc->txbusy && sc->txready) | |
608 | panic("DM9000: Internal error, trying to send without" | 608 | panic("DM9000: Internal error, trying to send without" | |
609 | " any empty queue\n"); | 609 | " any empty queue\n"); | |
610 | 610 | |||
611 | dme_prepare(sc, ifp); | 611 | dme_prepare(sc, ifp); | |
612 | 612 | |||
613 | if (sc->txbusy == 0) { | 613 | if (sc->txbusy == 0) { | |
614 | /* We are ready to transmit right away */ | 614 | /* We are ready to transmit right away */ | |
615 | dme_transmit(sc); | 615 | dme_transmit(sc); | |
616 | dme_prepare(sc, ifp); /* Prepare next one */ | 616 | dme_prepare(sc, ifp); /* Prepare next one */ | |
617 | } else { | 617 | } else { | |
618 | /* We need to wait until the current packet has | 618 | /* We need to wait until the current packet has | |
619 | * been transmitted. | 619 | * been transmitted. | |
620 | */ | 620 | */ | |
621 | ifp->if_flags |= IFF_OACTIVE; | 621 | ifp->if_flags |= IFF_OACTIVE; | |
622 | } | 622 | } | |
623 | 623 | |||
624 | DPRINTF(("dme_start_output: End\n")); | 624 | DPRINTF(("dme_start_output: End\n")); | |
625 | } | 625 | } | |
626 | 626 | |||
627 | void | 627 | void | |
628 | dme_prepare(struct dme_softc *sc, struct ifnet *ifp) | 628 | dme_prepare(struct dme_softc *sc, struct ifnet *ifp) | |
629 | { | 629 | { | |
630 | struct mbuf *bufChain; | 630 | struct mbuf *bufChain; | |
631 | uint16_t length; | 631 | uint16_t length; | |
632 | 632 | |||
633 | TX_DPRINTF(("dme_prepare: Entering\n")); | 633 | TX_DPRINTF(("dme_prepare: Entering\n")); | |
634 | 634 | |||
635 | if (sc->txready) | 635 | if (sc->txready) | |
636 | panic("dme_prepare: Someone called us with txready set\n"); | 636 | panic("dme_prepare: Someone called us with txready set\n"); | |
637 | 637 | |||
638 | IFQ_DEQUEUE(&ifp->if_snd, bufChain); | 638 | IFQ_DEQUEUE(&ifp->if_snd, bufChain); | |
639 | if (bufChain == NULL) { | 639 | if (bufChain == NULL) { | |
640 | TX_DPRINTF(("dme_prepare: Nothing to transmit\n")); | 640 | TX_DPRINTF(("dme_prepare: Nothing to transmit\n")); | |
641 | ifp->if_flags &= ~IFF_OACTIVE; /* Clear OACTIVE bit */ | 641 | ifp->if_flags &= ~IFF_OACTIVE; /* Clear OACTIVE bit */ | |
642 | return; /* Nothing to transmit */ | 642 | return; /* Nothing to transmit */ | |
643 | } | 643 | } | |
644 | 644 | |||
645 | /* Element has now been removed from the queue, so we better send it */ | 645 | /* Element has now been removed from the queue, so we better send it */ | |
646 | 646 | |||
647 | bpf_mtap(ifp, bufChain, BPF_D_OUT); | 647 | bpf_mtap(ifp, bufChain, BPF_D_OUT); | |
648 | 648 | |||
649 | /* Setup the DM9000 to accept the writes, and then write each buf in | 649 | /* Setup the DM9000 to accept the writes, and then write each buf in | |
650 | the chain. */ | 650 | the chain. */ | |
651 | 651 | |||
652 | TX_DATA_DPRINTF(("dme_prepare: Writing data: ")); | 652 | TX_DATA_DPRINTF(("dme_prepare: Writing data: ")); | |
653 | bus_space_write_1(sc->sc_iot, sc->sc_ioh, sc->dme_io, DM9000_MWCMD); | 653 | bus_space_write_1(sc->sc_iot, sc->sc_ioh, sc->dme_io, DM9000_MWCMD); | |
654 | length = sc->sc_pkt_write(sc, bufChain); | 654 | length = sc->sc_pkt_write(sc, bufChain); | |
655 | TX_DATA_DPRINTF(("\n")); | 655 | TX_DATA_DPRINTF(("\n")); | |
656 | 656 | |||
657 | if (length % sc->sc_data_width != 0) | 657 | if (length % sc->sc_data_width != 0) | |
658 | panic("dme_prepare: length is not compatible with IO_MODE"); | 658 | panic("dme_prepare: length is not compatible with IO_MODE"); | |
659 | 659 | |||
660 | sc->txready_length = length; | 660 | sc->txready_length = length; | |
661 | sc->txready = 1; | 661 | sc->txready = 1; | |
662 | 662 | |||
663 | TX_DPRINTF(("dme_prepare: txbusy: %d\ndme_prepare: " | 663 | TX_DPRINTF(("dme_prepare: txbusy: %d\ndme_prepare: " | |
664 | "txready: %d, txready_length: %d\n", | 664 | "txready: %d, txready_length: %d\n", | |
665 | sc->txbusy, sc->txready, sc->txready_length)); | 665 | sc->txbusy, sc->txready, sc->txready_length)); | |
666 | 666 | |||
667 | m_freem(bufChain); | 667 | m_freem(bufChain); | |
668 | 668 | |||
669 | TX_DPRINTF(("dme_prepare: Leaving\n")); | 669 | TX_DPRINTF(("dme_prepare: Leaving\n")); | |
670 | } | 670 | } | |
671 | 671 | |||
672 | int | 672 | int | |
673 | dme_init(struct ifnet *ifp) | 673 | dme_init(struct ifnet *ifp) | |
674 | { | 674 | { | |
675 | int s; | 675 | int s; | |
676 | struct dme_softc *sc = ifp->if_softc; | 676 | struct dme_softc *sc = ifp->if_softc; | |
677 | 677 | |||
678 | dme_stop(ifp, 0); | 678 | dme_stop(ifp, 0); | |
679 | 679 | |||
680 | s = splnet(); | 680 | s = splnet(); | |
681 | 681 | |||
682 | dme_reset(sc); | 682 | dme_reset(sc); | |
683 | 683 | |||
684 | sc->sc_ethercom.ec_if.if_flags |= IFF_RUNNING; | 684 | sc->sc_ethercom.ec_if.if_flags |= IFF_RUNNING; | |
685 | sc->sc_ethercom.ec_if.if_flags &= ~IFF_OACTIVE; | 685 | sc->sc_ethercom.ec_if.if_flags &= ~IFF_OACTIVE; | |
686 | sc->sc_ethercom.ec_if.if_timer = 0; | 686 | sc->sc_ethercom.ec_if.if_timer = 0; | |
687 | 687 | |||
688 | splx(s); | 688 | splx(s); | |
689 | 689 | |||
690 | return 0; | 690 | return 0; | |
691 | } | 691 | } | |
692 | 692 | |||
693 | int | 693 | int | |
694 | dme_ioctl(struct ifnet *ifp, u_long cmd, void *data) | 694 | dme_ioctl(struct ifnet *ifp, u_long cmd, void *data) | |
695 | { | 695 | { | |
696 | struct dme_softc *sc = ifp->if_softc; | 696 | struct dme_softc *sc = ifp->if_softc; | |
697 | int s, error = 0; | 697 | int s, error = 0; | |
698 | 698 | |||
699 | s = splnet(); | 699 | s = splnet(); | |
700 | 700 | |||
701 | switch (cmd) { | 701 | switch (cmd) { | |
702 | default: | 702 | default: | |
703 | error = ether_ioctl(ifp, cmd, data); | 703 | error = ether_ioctl(ifp, cmd, data); | |
704 | if (error == ENETRESET) { | 704 | if (error == ENETRESET) { | |
705 | if (ifp->if_flags && IFF_RUNNING) { | 705 | if (ifp->if_flags && IFF_RUNNING) { | |
706 | /* Address list has changed, reconfigure | 706 | /* Address list has changed, reconfigure | |
707 | filter */ | 707 | filter */ | |
708 | dme_set_addr_filter(sc); | 708 | dme_set_addr_filter(sc); | |
709 | } | 709 | } | |
710 | error = 0; | 710 | error = 0; | |
711 | } | 711 | } | |
712 | break; | 712 | break; | |
713 | } | 713 | } | |
714 | 714 | |||
715 | splx(s); | 715 | splx(s); | |
716 | return error; | 716 | return error; | |
717 | } | 717 | } | |
718 | 718 | |||
719 | void | 719 | void | |
720 | dme_stop(struct ifnet *ifp, int disable) | 720 | dme_stop(struct ifnet *ifp, int disable) | |
721 | { | 721 | { | |
722 | struct dme_softc *sc = ifp->if_softc; | 722 | struct dme_softc *sc = ifp->if_softc; | |
723 | 723 | |||
724 | /* Not quite sure what to do when called with disable == 0 */ | 724 | /* Not quite sure what to do when called with disable == 0 */ | |
725 | if (disable) { | 725 | if (disable) { | |
726 | /* Disable RX */ | 726 | /* Disable RX */ | |
727 | dme_write(sc, DM9000_RCR, 0x0); | 727 | dme_write(sc, DM9000_RCR, 0x0); | |
728 | } | 728 | } | |
729 | 729 | |||
730 | ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); | 730 | ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); | |
731 | ifp->if_timer = 0; | 731 | ifp->if_timer = 0; | |
732 | } | 732 | } | |
733 | 733 | |||
734 | int | 734 | int | |
735 | dme_mediachange(struct ifnet *ifp) | 735 | dme_mediachange(struct ifnet *ifp) | |
736 | { | 736 | { | |
737 | struct dme_softc *sc = ifp->if_softc; | 737 | struct dme_softc *sc = ifp->if_softc; | |
738 | 738 | |||
739 | return dme_set_media(sc, sc->sc_media.ifm_cur->ifm_media); | 739 | return dme_set_media(sc, sc->sc_media.ifm_cur->ifm_media); | |
740 | } | 740 | } | |
741 | 741 | |||
742 | void | 742 | void | |
743 | dme_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr) | 743 | dme_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr) | |
744 | { | 744 | { | |
745 | struct dme_softc *sc = ifp->if_softc; | 745 | struct dme_softc *sc = ifp->if_softc; | |
746 | 746 | |||
747 | ifmr->ifm_active = sc->sc_media_active; | 747 | ifmr->ifm_active = sc->sc_media_active; | |
748 | ifmr->ifm_status = sc->sc_media_status; | 748 | ifmr->ifm_status = sc->sc_media_status; | |
749 | } | 749 | } | |
750 | 750 | |||
751 | void | 751 | void | |
752 | dme_transmit(struct dme_softc *sc) | 752 | dme_transmit(struct dme_softc *sc) | |
753 | { | 753 | { | |
754 | 754 | |||
755 | TX_DPRINTF(("dme_transmit: PRE: txready: %d, txbusy: %d\n", | 755 | TX_DPRINTF(("dme_transmit: PRE: txready: %d, txbusy: %d\n", | |
756 | sc->txready, sc->txbusy)); | 756 | sc->txready, sc->txbusy)); | |
757 | 757 | |||
758 | dme_write(sc, DM9000_TXPLL, sc->txready_length & 0xff); | 758 | dme_write(sc, DM9000_TXPLL, sc->txready_length & 0xff); | |
759 | dme_write(sc, DM9000_TXPLH, (sc->txready_length >> 8) & 0xff ); | 759 | dme_write(sc, DM9000_TXPLH, (sc->txready_length >> 8) & 0xff ); | |
760 | 760 | |||
761 | /* Request to send the packet */ | 761 | /* Request to send the packet */ | |
762 | dme_read(sc, DM9000_ISR); | 762 | dme_read(sc, DM9000_ISR); | |
763 | 763 | |||
764 | dme_write(sc, DM9000_TCR, DM9000_TCR_TXREQ); | 764 | dme_write(sc, DM9000_TCR, DM9000_TCR_TXREQ); | |
765 | 765 | |||
766 | sc->txready = 0; | 766 | sc->txready = 0; | |
767 | sc->txbusy = 1; | 767 | sc->txbusy = 1; | |
768 | sc->txready_length = 0; | 768 | sc->txready_length = 0; | |
769 | } | 769 | } | |
770 | 770 | |||
771 | void | 771 | void | |
772 | dme_receive(struct dme_softc *sc, struct ifnet *ifp) | 772 | dme_receive(struct dme_softc *sc, struct ifnet *ifp) | |
773 | { | 773 | { | |
774 | uint8_t ready = 0x01; | 774 | uint8_t ready = 0x01; | |
775 | 775 | |||
776 | DPRINTF(("inside dme_receive\n")); | 776 | DPRINTF(("inside dme_receive\n")); | |
777 | 777 | |||
778 | while (ready == 0x01) { | 778 | while (ready == 0x01) { | |
779 | /* Packet received, retrieve it */ | 779 | /* Packet received, retrieve it */ | |
780 | 780 | |||
781 | /* Read without address increment to get the ready byte without | 781 | /* Read without address increment to get the ready byte without | |
782 | moving past it. */ | 782 | moving past it. */ | |
783 | bus_space_write_1(sc->sc_iot, sc->sc_ioh, | 783 | bus_space_write_1(sc->sc_iot, sc->sc_ioh, | |
784 | sc->dme_io, DM9000_MRCMDX); | 784 | sc->dme_io, DM9000_MRCMDX); | |
785 | /* Dummy ready */ | 785 | /* Dummy ready */ | |
786 | ready = bus_space_read_1(sc->sc_iot, sc->sc_ioh, sc->dme_data); | 786 | ready = bus_space_read_1(sc->sc_iot, sc->sc_ioh, sc->dme_data); | |
787 | ready = bus_space_read_1(sc->sc_iot, sc->sc_ioh, sc->dme_data); | 787 | ready = bus_space_read_1(sc->sc_iot, sc->sc_ioh, sc->dme_data); | |
788 | ready &= 0x03; /* we only want bits 1:0 */ | 788 | ready &= 0x03; /* we only want bits 1:0 */ | |
789 | if (ready == 0x01) { | 789 | if (ready == 0x01) { | |
790 | uint8_t rx_status; | 790 | uint8_t rx_status; | |
791 | struct mbuf *m; | 791 | struct mbuf *m; | |
792 | 792 | |||
793 | /* Read with address increment. */ | 793 | /* Read with address increment. */ | |
794 | bus_space_write_1(sc->sc_iot, sc->sc_ioh, | 794 | bus_space_write_1(sc->sc_iot, sc->sc_ioh, | |
795 | sc->dme_io, DM9000_MRCMD); | 795 | sc->dme_io, DM9000_MRCMD); | |
796 | 796 | |||
797 | rx_status = sc->sc_pkt_read(sc, ifp, &m); | 797 | rx_status = sc->sc_pkt_read(sc, ifp, &m); | |
798 | if (m == NULL) { | 798 | if (m == NULL) { | |
799 | /* failed to allocate a receive buffer */ | 799 | /* failed to allocate a receive buffer */ | |
800 | ifp->if_ierrors++; | 800 | if_statinc(ifp, if_ierrors); | |
801 | RX_DPRINTF(("dme_receive: " | 801 | RX_DPRINTF(("dme_receive: " | |
802 | "Error allocating buffer\n")); | 802 | "Error allocating buffer\n")); | |
803 | } else if (rx_status & (DM9000_RSR_CE | DM9000_RSR_PLE)) { | 803 | } else if (rx_status & (DM9000_RSR_CE | DM9000_RSR_PLE)) { | |
804 | /* Error while receiving the packet, | 804 | /* Error while receiving the packet, | |
805 | * discard it and keep track of counters | 805 | * discard it and keep track of counters | |
806 | */ | 806 | */ | |
807 | ifp->if_ierrors++; | 807 | if_statinc(ifp, if_ierrors); | |
808 | RX_DPRINTF(("dme_receive: " | 808 | RX_DPRINTF(("dme_receive: " | |
809 | "Error reciving packet\n")); | 809 | "Error reciving packet\n")); | |
810 | } else if (rx_status & DM9000_RSR_LCS) { | 810 | } else if (rx_status & DM9000_RSR_LCS) { | |
811 | ifp->if_collisions++; | 811 | if_statinc(ifp, if_collisions); | |
812 | } else { | 812 | } else { | |
813 | if_percpuq_enqueue(ifp->if_percpuq, m); | 813 | if_percpuq_enqueue(ifp->if_percpuq, m); | |
814 | } | 814 | } | |
815 | 815 | |||
816 | } else if (ready != 0x00) { | 816 | } else if (ready != 0x00) { | |
817 | /* Should this be logged somehow? */ | 817 | /* Should this be logged somehow? */ | |
818 | printf("%s: Resetting chip\n", | 818 | printf("%s: Resetting chip\n", | |
819 | device_xname(sc->sc_dev)); | 819 | device_xname(sc->sc_dev)); | |
820 | dme_reset(sc); | 820 | dme_reset(sc); | |
821 | } | 821 | } | |
822 | } | 822 | } | |
823 | } | 823 | } | |
824 | 824 | |||
825 | void | 825 | void | |
826 | dme_reset(struct dme_softc *sc) | 826 | dme_reset(struct dme_softc *sc) | |
827 | { | 827 | { | |
828 | uint8_t var; | 828 | uint8_t var; | |
829 | 829 | |||
830 | /* We only re-initialized the PHY in this function the first time it is | 830 | /* We only re-initialized the PHY in this function the first time it is | |
831 | called. */ | 831 | called. */ | |
832 | if (!sc->sc_phy_initialized) { | 832 | if (!sc->sc_phy_initialized) { | |
833 | /* PHY Reset */ | 833 | /* PHY Reset */ | |
834 | dme_phy_write(sc, DM9000_PHY_BMCR, DM9000_PHY_BMCR_RESET); | 834 | dme_phy_write(sc, DM9000_PHY_BMCR, DM9000_PHY_BMCR_RESET); | |
835 | 835 | |||
836 | /* PHY Power Down */ | 836 | /* PHY Power Down */ | |
837 | var = dme_read(sc, DM9000_GPR); | 837 | var = dme_read(sc, DM9000_GPR); | |
838 | dme_write(sc, DM9000_GPR, var | DM9000_GPR_PHY_PWROFF); | 838 | dme_write(sc, DM9000_GPR, var | DM9000_GPR_PHY_PWROFF); | |
839 | } | 839 | } | |
840 | 840 | |||
841 | /* Reset the DM9000 twice, as described in section 2 of the Programming | 841 | /* Reset the DM9000 twice, as described in section 2 of the Programming | |
842 | Guide. | 842 | Guide. | |
843 | The PHY is initialized and enabled between those two resets. | 843 | The PHY is initialized and enabled between those two resets. | |
844 | */ | 844 | */ | |
845 | 845 | |||
846 | /* Software Reset*/ | 846 | /* Software Reset*/ | |
847 | dme_write(sc, DM9000_NCR, | 847 | dme_write(sc, DM9000_NCR, | |
848 | DM9000_NCR_RST | DM9000_NCR_LBK_MAC_INTERNAL); | 848 | DM9000_NCR_RST | DM9000_NCR_LBK_MAC_INTERNAL); | |
849 | delay(20); | 849 | delay(20); | |
850 | dme_write(sc, DM9000_NCR, 0x0); | 850 | dme_write(sc, DM9000_NCR, 0x0); | |
851 | 851 | |||
852 | if (!sc->sc_phy_initialized) { | 852 | if (!sc->sc_phy_initialized) { | |
853 | /* PHY Initialization */ | 853 | /* PHY Initialization */ | |
854 | dme_phy_init(sc); | 854 | dme_phy_init(sc); | |
855 | 855 | |||
856 | /* PHY Enable */ | 856 | /* PHY Enable */ | |
857 | var = dme_read(sc, DM9000_GPR); | 857 | var = dme_read(sc, DM9000_GPR); | |
858 | dme_write(sc, DM9000_GPR, var & ~DM9000_GPR_PHY_PWROFF); | 858 | dme_write(sc, DM9000_GPR, var & ~DM9000_GPR_PHY_PWROFF); | |
859 | var = dme_read(sc, DM9000_GPCR); | 859 | var = dme_read(sc, DM9000_GPCR); | |
860 | dme_write(sc, DM9000_GPCR, var | DM9000_GPCR_GPIO0_OUT); | 860 | dme_write(sc, DM9000_GPCR, var | DM9000_GPCR_GPIO0_OUT); | |
861 | 861 | |||
862 | dme_write(sc, DM9000_NCR, | 862 | dme_write(sc, DM9000_NCR, | |
863 | DM9000_NCR_RST | DM9000_NCR_LBK_MAC_INTERNAL); | 863 | DM9000_NCR_RST | DM9000_NCR_LBK_MAC_INTERNAL); | |
864 | delay(20); | 864 | delay(20); | |
865 | dme_write(sc, DM9000_NCR, 0x0); | 865 | dme_write(sc, DM9000_NCR, 0x0); | |
866 | } | 866 | } | |
867 | 867 | |||
868 | /* Select internal PHY, no wakeup event, no collosion mode, | 868 | /* Select internal PHY, no wakeup event, no collosion mode, | |
869 | * normal loopback mode. | 869 | * normal loopback mode. | |
870 | */ | 870 | */ | |
871 | dme_write(sc, DM9000_NCR, DM9000_NCR_LBK_NORMAL ); | 871 | dme_write(sc, DM9000_NCR, DM9000_NCR_LBK_NORMAL ); | |
872 | 872 | |||
873 | /* Will clear TX1END, TX2END, and WAKEST fields by reading DM9000_NSR*/ | 873 | /* Will clear TX1END, TX2END, and WAKEST fields by reading DM9000_NSR*/ | |
874 | dme_read(sc, DM9000_NSR); | 874 | dme_read(sc, DM9000_NSR); | |
875 | 875 | |||
876 | /* Enable wraparound of read/write pointer, packet received latch, | 876 | /* Enable wraparound of read/write pointer, packet received latch, | |
877 | * and packet transmitted latch. | 877 | * and packet transmitted latch. | |
878 | */ | 878 | */ | |
879 | dme_write(sc, DM9000_IMR, | 879 | dme_write(sc, DM9000_IMR, | |
880 | DM9000_IMR_PAR | DM9000_IMR_PRM | DM9000_IMR_PTM); | 880 | DM9000_IMR_PAR | DM9000_IMR_PRM | DM9000_IMR_PTM); | |
881 | 881 | |||
882 | /* Setup multicast address filter, and enable RX. */ | 882 | /* Setup multicast address filter, and enable RX. */ | |
883 | dme_set_addr_filter(sc); | 883 | dme_set_addr_filter(sc); | |
884 | 884 | |||
885 | /* Obtain media information from PHY */ | 885 | /* Obtain media information from PHY */ | |
886 | dme_phy_update_media(sc); | 886 | dme_phy_update_media(sc); | |
887 | 887 | |||
888 | sc->txbusy = 0; | 888 | sc->txbusy = 0; | |
889 | sc->txready = 0; | 889 | sc->txready = 0; | |
890 | sc->sc_phy_initialized = 1; | 890 | sc->sc_phy_initialized = 1; | |
891 | } | 891 | } | |
892 | 892 | |||
893 | void | 893 | void | |
894 | dme_set_addr_filter(struct dme_softc *sc) | 894 | dme_set_addr_filter(struct dme_softc *sc) | |
895 | { | 895 | { | |
896 | struct ether_multi *enm; | 896 | struct ether_multi *enm; | |
897 | struct ether_multistep step; | 897 | struct ether_multistep step; | |
898 | struct ethercom *ec; | 898 | struct ethercom *ec; | |
899 | struct ifnet *ifp; | 899 | struct ifnet *ifp; | |
900 | uint16_t af[4]; | 900 | uint16_t af[4]; | |
901 | int i; | 901 | int i; | |
902 | 902 | |||
903 | ec = &sc->sc_ethercom; | 903 | ec = &sc->sc_ethercom; | |
904 | ifp = &ec->ec_if; | 904 | ifp = &ec->ec_if; | |
905 | 905 | |||
906 | if (ifp->if_flags & IFF_PROMISC) { | 906 | if (ifp->if_flags & IFF_PROMISC) { | |
907 | dme_write(sc, DM9000_RCR, DM9000_RCR_RXEN | | 907 | dme_write(sc, DM9000_RCR, DM9000_RCR_RXEN | | |
908 | DM9000_RCR_WTDIS | | 908 | DM9000_RCR_WTDIS | | |
909 | DM9000_RCR_PRMSC); | 909 | DM9000_RCR_PRMSC); | |
910 | ifp->if_flags |= IFF_ALLMULTI; | 910 | ifp->if_flags |= IFF_ALLMULTI; | |
911 | return; | 911 | return; | |
912 | } | 912 | } | |
913 | 913 | |||
914 | af[0] = af[1] = af[2] = af[3] = 0x0000; | 914 | af[0] = af[1] = af[2] = af[3] = 0x0000; | |
915 | ifp->if_flags &= ~IFF_ALLMULTI; | 915 | ifp->if_flags &= ~IFF_ALLMULTI; | |
916 | 916 | |||
917 | ETHER_LOCK(ec); | 917 | ETHER_LOCK(ec); | |
918 | ETHER_FIRST_MULTI(step, ec, enm); | 918 | ETHER_FIRST_MULTI(step, ec, enm); | |
919 | while (enm != NULL) { | 919 | while (enm != NULL) { | |
920 | uint16_t hash; | 920 | uint16_t hash; | |
921 | if (memcpy(enm->enm_addrlo, enm->enm_addrhi, | 921 | if (memcpy(enm->enm_addrlo, enm->enm_addrhi, | |
922 | sizeof(enm->enm_addrlo))) { | 922 | sizeof(enm->enm_addrlo))) { | |
923 | /* | 923 | /* | |
924 | * We must listen to a range of multicast addresses. | 924 | * We must listen to a range of multicast addresses. | |
925 | * For now, just accept all multicasts, rather than | 925 | * For now, just accept all multicasts, rather than | |
926 | * trying to set only those filter bits needed to match | 926 | * trying to set only those filter bits needed to match | |
927 | * the range. (At this time, the only use of address | 927 | * the range. (At this time, the only use of address | |
928 | * ranges is for IP multicast routing, for which the | 928 | * ranges is for IP multicast routing, for which the | |
929 | * range is big enough to require all bits set.) | 929 | * range is big enough to require all bits set.) | |
930 | */ | 930 | */ | |
931 | ifp->if_flags |= IFF_ALLMULTI; | 931 | ifp->if_flags |= IFF_ALLMULTI; | |
932 | af[0] = af[1] = af[2] = af[3] = 0xffff; | 932 | af[0] = af[1] = af[2] = af[3] = 0xffff; | |
933 | break; | 933 | break; | |
934 | } else { | 934 | } else { | |
935 | hash = ether_crc32_le(enm->enm_addrlo, ETHER_ADDR_LEN) & 0x3F; | 935 | hash = ether_crc32_le(enm->enm_addrlo, ETHER_ADDR_LEN) & 0x3F; | |
936 | af[(uint16_t)(hash>>4)] |= (uint16_t)(1 << (hash % 16)); | 936 | af[(uint16_t)(hash>>4)] |= (uint16_t)(1 << (hash % 16)); | |
937 | ETHER_NEXT_MULTI(step, enm); | 937 | ETHER_NEXT_MULTI(step, enm); | |
938 | } | 938 | } | |
939 | } | 939 | } | |
940 | ETHER_UNLOCK(ec); | 940 | ETHER_UNLOCK(ec); | |
941 | 941 | |||
942 | /* Write the multicast address filter */ | 942 | /* Write the multicast address filter */ | |
943 | for (i = 0; i < 4; i++) { | 943 | for (i = 0; i < 4; i++) { | |
944 | dme_write(sc, DM9000_MAB0+i*2, af[i] & 0xFF); | 944 | dme_write(sc, DM9000_MAB0+i*2, af[i] & 0xFF); | |
945 | dme_write(sc, DM9000_MAB0+i*2+1, (af[i] >> 8) & 0xFF); | 945 | dme_write(sc, DM9000_MAB0+i*2+1, (af[i] >> 8) & 0xFF); | |
946 | } | 946 | } | |
947 | 947 | |||
948 | /* Setup RX controls */ | 948 | /* Setup RX controls */ | |
949 | dme_write(sc, DM9000_RCR, DM9000_RCR_RXEN | DM9000_RCR_WTDIS); | 949 | dme_write(sc, DM9000_RCR, DM9000_RCR_RXEN | DM9000_RCR_WTDIS); | |
950 | } | 950 | } | |
951 | 951 | |||
952 | int | 952 | int | |
953 | dme_pkt_write_2(struct dme_softc *sc, struct mbuf *bufChain) | 953 | dme_pkt_write_2(struct dme_softc *sc, struct mbuf *bufChain) | |
954 | { | 954 | { | |
955 | int left_over_count = 0; /* Number of bytes from previous mbuf, which | 955 | int left_over_count = 0; /* Number of bytes from previous mbuf, which | |
956 | need to be written with the next.*/ | 956 | need to be written with the next.*/ | |
957 | uint16_t left_over_buf = 0; | 957 | uint16_t left_over_buf = 0; | |
958 | int length = 0; | 958 | int length = 0; | |
959 | struct mbuf *buf; | 959 | struct mbuf *buf; | |
960 | uint8_t *write_ptr; | 960 | uint8_t *write_ptr; | |
961 | 961 | |||
962 | /* We expect that the DM9000 has been setup to accept writes before | 962 | /* We expect that the DM9000 has been setup to accept writes before | |
963 | this function is called. */ | 963 | this function is called. */ | |
964 | 964 | |||
965 | for (buf = bufChain; buf != NULL; buf = buf->m_next) { | 965 | for (buf = bufChain; buf != NULL; buf = buf->m_next) { | |
966 | int to_write = buf->m_len; | 966 | int to_write = buf->m_len; | |
967 | 967 | |||
968 | length += to_write; | 968 | length += to_write; | |
969 | 969 | |||
970 | write_ptr = buf->m_data; | 970 | write_ptr = buf->m_data; | |
971 | while (to_write > 0 || | 971 | while (to_write > 0 || | |
972 | (buf->m_next == NULL && left_over_count > 0)) { | 972 | (buf->m_next == NULL && left_over_count > 0)) { | |
973 | if (left_over_count > 0) { | 973 | if (left_over_count > 0) { | |
974 | uint8_t b = 0; | 974 | uint8_t b = 0; | |
975 | DPRINTF(("dme_pkt_write_16: " | 975 | DPRINTF(("dme_pkt_write_16: " | |
976 | "Writing left over byte\n")); | 976 | "Writing left over byte\n")); | |
977 | 977 | |||
978 | if (to_write > 0) { | 978 | if (to_write > 0) { | |
979 | b = *write_ptr; | 979 | b = *write_ptr; | |
980 | to_write--; | 980 | to_write--; | |
981 | write_ptr++; | 981 | write_ptr++; | |
982 | 982 | |||
983 | DPRINTF(("Took single byte\n")); | 983 | DPRINTF(("Took single byte\n")); | |
984 | } else { | 984 | } else { | |
985 | DPRINTF(("Leftover in last run\n")); | 985 | DPRINTF(("Leftover in last run\n")); | |
986 | length++; | 986 | length++; | |
987 | } | 987 | } | |
988 | 988 | |||
989 | /* Does shift direction depend on endianess? */ | 989 | /* Does shift direction depend on endianess? */ | |
990 | left_over_buf = left_over_buf | (b << 8); | 990 | left_over_buf = left_over_buf | (b << 8); | |
991 | 991 | |||
992 | bus_space_write_2(sc->sc_iot, sc->sc_ioh, | 992 | bus_space_write_2(sc->sc_iot, sc->sc_ioh, | |
993 | sc->dme_data, left_over_buf); | 993 | sc->dme_data, left_over_buf); | |
994 | TX_DATA_DPRINTF(("%02X ", left_over_buf)); | 994 | TX_DATA_DPRINTF(("%02X ", left_over_buf)); | |
995 | left_over_count = 0; | 995 | left_over_count = 0; | |
996 | } else if ((long)write_ptr % 2 != 0) { | 996 | } else if ((long)write_ptr % 2 != 0) { | |
997 | /* Misaligned data */ | 997 | /* Misaligned data */ | |
998 | DPRINTF(("dme_pkt_write_16: " | 998 | DPRINTF(("dme_pkt_write_16: " | |
999 | "Detected misaligned data\n")); | 999 | "Detected misaligned data\n")); | |
1000 | left_over_buf = *write_ptr; | 1000 | left_over_buf = *write_ptr; | |
1001 | left_over_count = 1; | 1001 | left_over_count = 1; | |
1002 | write_ptr++; | 1002 | write_ptr++; | |
1003 | to_write--; | 1003 | to_write--; | |
1004 | } else { | 1004 | } else { | |
1005 | int i; | 1005 | int i; | |
1006 | uint16_t *dptr = (uint16_t *)write_ptr; | 1006 | uint16_t *dptr = (uint16_t *)write_ptr; | |
1007 | 1007 | |||
1008 | /* A block of aligned data. */ | 1008 | /* A block of aligned data. */ | |
1009 | for (i = 0; i < to_write / 2; i++) { | 1009 | for (i = 0; i < to_write / 2; i++) { | |
1010 | /* buf will be half-word aligned | 1010 | /* buf will be half-word aligned | |
1011 | * all the time | 1011 | * all the time | |
1012 | */ | 1012 | */ | |
1013 | bus_space_write_2(sc->sc_iot, | 1013 | bus_space_write_2(sc->sc_iot, | |
1014 | sc->sc_ioh, sc->dme_data, *dptr); | 1014 | sc->sc_ioh, sc->dme_data, *dptr); | |
1015 | TX_DATA_DPRINTF(("%02X %02X ", | 1015 | TX_DATA_DPRINTF(("%02X %02X ", | |
1016 | *dptr & 0xFF, (*dptr >> 8) & 0xFF)); | 1016 | *dptr & 0xFF, (*dptr >> 8) & 0xFF)); | |
1017 | dptr++; | 1017 | dptr++; | |
1018 | } | 1018 | } | |
1019 | 1019 | |||
1020 | write_ptr += i * 2; | 1020 | write_ptr += i * 2; | |
1021 | if (to_write % 2 != 0) { | 1021 | if (to_write % 2 != 0) { | |
1022 | DPRINTF(("dme_pkt_write_16: " | 1022 | DPRINTF(("dme_pkt_write_16: " | |
1023 | "to_write %% 2: %d\n", | 1023 | "to_write %% 2: %d\n", | |
1024 | to_write % 2)); | 1024 | to_write % 2)); | |
1025 | left_over_count = 1; | 1025 | left_over_count = 1; | |
1026 | /* XXX: Does this depend on | 1026 | /* XXX: Does this depend on | |
1027 | * the endianess? | 1027 | * the endianess? | |
1028 | */ | 1028 | */ | |
1029 | left_over_buf = *write_ptr; | 1029 | left_over_buf = *write_ptr; | |
1030 | 1030 | |||
1031 | write_ptr++; | 1031 | write_ptr++; | |
1032 | to_write--; | 1032 | to_write--; | |
1033 | DPRINTF(("dme_pkt_write_16: " | 1033 | DPRINTF(("dme_pkt_write_16: " | |
1034 | "to_write (after): %d\n", | 1034 | "to_write (after): %d\n", | |
1035 | to_write)); | 1035 | to_write)); | |
1036 | DPRINTF(("dme_pkt_write_16: i * 2: %d\n", | 1036 | DPRINTF(("dme_pkt_write_16: i * 2: %d\n", | |
1037 | i*2)); | 1037 | i*2)); | |
1038 | } | 1038 | } | |
1039 | to_write -= i * 2; | 1039 | to_write -= i * 2; | |
1040 | } | 1040 | } | |
1041 | } /* while (...) */ | 1041 | } /* while (...) */ | |
1042 | } /* for (...) */ | 1042 | } /* for (...) */ | |
1043 | 1043 | |||
1044 | return length; | 1044 | return length; | |
1045 | } | 1045 | } | |
1046 | 1046 | |||
1047 | int | 1047 | int | |
1048 | dme_pkt_read_2(struct dme_softc *sc, struct ifnet *ifp, struct mbuf **outBuf) | 1048 | dme_pkt_read_2(struct dme_softc *sc, struct ifnet *ifp, struct mbuf **outBuf) | |
1049 | { | 1049 | { | |
1050 | uint8_t rx_status; | 1050 | uint8_t rx_status; | |
1051 | struct mbuf *m; | 1051 | struct mbuf *m; | |
1052 | uint16_t data; | 1052 | uint16_t data; | |
1053 | uint16_t frame_length; | 1053 | uint16_t frame_length; | |
1054 | uint16_t i; | 1054 | uint16_t i; | |
1055 | uint16_t *buf; | 1055 | uint16_t *buf; | |
1056 | 1056 | |||
1057 | data = bus_space_read_2(sc->sc_iot, sc->sc_ioh, sc->dme_data); | 1057 | data = bus_space_read_2(sc->sc_iot, sc->sc_ioh, sc->dme_data); | |
1058 | 1058 | |||
1059 | rx_status = data & 0xFF; | 1059 | rx_status = data & 0xFF; | |
1060 | frame_length = bus_space_read_2(sc->sc_iot, | 1060 | frame_length = bus_space_read_2(sc->sc_iot, | |
1061 | sc->sc_ioh, sc->dme_data); | 1061 | sc->sc_ioh, sc->dme_data); | |
1062 | if (frame_length > ETHER_MAX_LEN) { | 1062 | if (frame_length > ETHER_MAX_LEN) { | |
1063 | printf("Got frame of length: %d\n", frame_length); | 1063 | printf("Got frame of length: %d\n", frame_length); | |
1064 | printf("ETHER_MAX_LEN is: %d\n", ETHER_MAX_LEN); | 1064 | printf("ETHER_MAX_LEN is: %d\n", ETHER_MAX_LEN); | |
1065 | panic("Something is rotten"); | 1065 | panic("Something is rotten"); | |
1066 | } | 1066 | } | |
1067 | RX_DPRINTF(("dme_receive: rx_statux: 0x%x, frame_length: %d\n", | 1067 | RX_DPRINTF(("dme_receive: rx_statux: 0x%x, frame_length: %d\n", | |
1068 | rx_status, frame_length)); | 1068 | rx_status, frame_length)); | |
1069 | 1069 | |||
1070 | 1070 | |||
1071 | m = dme_alloc_receive_buffer(ifp, frame_length); | 1071 | m = dme_alloc_receive_buffer(ifp, frame_length); | |
1072 | if (m == NULL) { | 1072 | if (m == NULL) { | |
1073 | /* | 1073 | /* | |
1074 | * didn't get a receive buffer, so we read the rest of the | 1074 | * didn't get a receive buffer, so we read the rest of the | |
1075 | * packet, throw it away and return an error | 1075 | * packet, throw it away and return an error | |
1076 | */ | 1076 | */ | |
1077 | for (i = 0; i < frame_length; i += 2 ) { | 1077 | for (i = 0; i < frame_length; i += 2 ) { | |
1078 | data = bus_space_read_2(sc->sc_iot, | 1078 | data = bus_space_read_2(sc->sc_iot, | |
1079 | sc->sc_ioh, sc->dme_data); | 1079 | sc->sc_ioh, sc->dme_data); | |
1080 | } | 1080 | } | |
1081 | *outBuf = NULL; | 1081 | *outBuf = NULL; | |
1082 | return 0; | 1082 | return 0; | |
1083 | } | 1083 | } | |
1084 | 1084 | |||
1085 | buf = mtod(m, uint16_t*); | 1085 | buf = mtod(m, uint16_t*); | |
1086 | 1086 | |||
1087 | RX_DPRINTF(("dme_receive: ")); | 1087 | RX_DPRINTF(("dme_receive: ")); | |
1088 | 1088 | |||
1089 | for (i = 0; i < frame_length; i += 2 ) { | 1089 | for (i = 0; i < frame_length; i += 2 ) { | |
1090 | data = bus_space_read_2(sc->sc_iot, | 1090 | data = bus_space_read_2(sc->sc_iot, | |
1091 | sc->sc_ioh, sc->dme_data); | 1091 | sc->sc_ioh, sc->dme_data); | |
1092 | if ( (frame_length % 2 != 0) && | 1092 | if ( (frame_length % 2 != 0) && | |
1093 | (i == frame_length - 1) ) { | 1093 | (i == frame_length - 1) ) { | |
1094 | data = data & 0xff; | 1094 | data = data & 0xff; | |
1095 | RX_DPRINTF((" L ")); | 1095 | RX_DPRINTF((" L ")); | |
1096 | } | 1096 | } | |
1097 | *buf = data; | 1097 | *buf = data; | |
1098 | buf++; | 1098 | buf++; | |
1099 | RX_DATA_DPRINTF(("%02X %02X ", data & 0xff, | 1099 | RX_DATA_DPRINTF(("%02X %02X ", data & 0xff, | |
1100 | (data >> 8) & 0xff)); | 1100 | (data >> 8) & 0xff)); | |
1101 | } | 1101 | } | |
1102 | 1102 | |||
1103 | RX_DATA_DPRINTF(("\n")); | 1103 | RX_DATA_DPRINTF(("\n")); | |
1104 | RX_DPRINTF(("Read %d bytes\n", i)); | 1104 | RX_DPRINTF(("Read %d bytes\n", i)); | |
1105 | 1105 | |||
1106 | *outBuf = m; | 1106 | *outBuf = m; | |
1107 | return rx_status; | 1107 | return rx_status; | |
1108 | } | 1108 | } | |
1109 | 1109 | |||
1110 | int | 1110 | int | |
1111 | dme_pkt_write_1(struct dme_softc *sc, struct mbuf *bufChain) | 1111 | dme_pkt_write_1(struct dme_softc *sc, struct mbuf *bufChain) | |
1112 | { | 1112 | { | |
1113 | int length = 0, i; | 1113 | int length = 0, i; | |
1114 | struct mbuf *buf; | 1114 | struct mbuf *buf; | |
1115 | uint8_t *write_ptr; | 1115 | uint8_t *write_ptr; | |
1116 | 1116 | |||
1117 | /* | 1117 | /* | |
1118 | * We expect that the DM9000 has been setup to accept writes before | 1118 | * We expect that the DM9000 has been setup to accept writes before | |
1119 | * this function is called. | 1119 | * this function is called. | |
1120 | */ | 1120 | */ | |
1121 | 1121 | |||
1122 | for (buf = bufChain; buf != NULL; buf = buf->m_next) { | 1122 | for (buf = bufChain; buf != NULL; buf = buf->m_next) { | |
1123 | int to_write = buf->m_len; | 1123 | int to_write = buf->m_len; | |
1124 | 1124 | |||
1125 | length += to_write; | 1125 | length += to_write; | |
1126 | 1126 | |||
1127 | write_ptr = buf->m_data; | 1127 | write_ptr = buf->m_data; | |
1128 | for (i = 0; i < to_write; i++) { | 1128 | for (i = 0; i < to_write; i++) { | |
1129 | bus_space_write_1(sc->sc_iot, sc->sc_ioh, | 1129 | bus_space_write_1(sc->sc_iot, sc->sc_ioh, | |
1130 | sc->dme_data, *write_ptr); | 1130 | sc->dme_data, *write_ptr); | |
1131 | write_ptr++; | 1131 | write_ptr++; | |
1132 | } | 1132 | } | |
1133 | } /* for (...) */ | 1133 | } /* for (...) */ | |
1134 | 1134 | |||
1135 | return length; | 1135 | return length; | |
1136 | } | 1136 | } | |
1137 | 1137 | |||
1138 | int | 1138 | int | |
1139 | dme_pkt_read_1(struct dme_softc *sc, struct ifnet *ifp, struct mbuf **outBuf) | 1139 | dme_pkt_read_1(struct dme_softc *sc, struct ifnet *ifp, struct mbuf **outBuf) | |
1140 | { | 1140 | { | |
1141 | uint8_t rx_status; | 1141 | uint8_t rx_status; | |
1142 | struct mbuf *m; | 1142 | struct mbuf *m; | |
1143 | uint8_t *buf; | 1143 | uint8_t *buf; | |
1144 | uint16_t frame_length; | 1144 | uint16_t frame_length; | |
1145 | uint16_t i, reg; | 1145 | uint16_t i, reg; | |
1146 | uint8_t data; | 1146 | uint8_t data; | |
1147 | 1147 | |||
1148 | reg = bus_space_read_1(sc->sc_iot, sc->sc_ioh, sc->dme_data); | 1148 | reg = bus_space_read_1(sc->sc_iot, sc->sc_ioh, sc->dme_data); | |
1149 | reg |= bus_space_read_1(sc->sc_iot, sc->sc_ioh, sc->dme_data) << 8; | 1149 | reg |= bus_space_read_1(sc->sc_iot, sc->sc_ioh, sc->dme_data) << 8; | |
1150 | rx_status = reg & 0xFF; | 1150 | rx_status = reg & 0xFF; | |
1151 | 1151 | |||
1152 | reg = bus_space_read_1(sc->sc_iot, sc->sc_ioh, sc->dme_data); | 1152 | reg = bus_space_read_1(sc->sc_iot, sc->sc_ioh, sc->dme_data); | |
1153 | reg |= bus_space_read_1(sc->sc_iot, sc->sc_ioh, sc->dme_data) << 8; | 1153 | reg |= bus_space_read_1(sc->sc_iot, sc->sc_ioh, sc->dme_data) << 8; | |
1154 | frame_length = reg; | 1154 | frame_length = reg; | |
1155 | 1155 | |||
1156 | if (frame_length > ETHER_MAX_LEN) { | 1156 | if (frame_length > ETHER_MAX_LEN) { | |
1157 | printf("Got frame of length: %d\n", frame_length); | 1157 | printf("Got frame of length: %d\n", frame_length); | |
1158 | printf("ETHER_MAX_LEN is: %d\n", ETHER_MAX_LEN); | 1158 | printf("ETHER_MAX_LEN is: %d\n", ETHER_MAX_LEN); | |
1159 | panic("Something is rotten"); | 1159 | panic("Something is rotten"); | |
1160 | } | 1160 | } | |
1161 | RX_DPRINTF(("dme_receive: " | 1161 | RX_DPRINTF(("dme_receive: " | |
1162 | "rx_statux: 0x%x, frame_length: %d\n", | 1162 | "rx_statux: 0x%x, frame_length: %d\n", | |
1163 | rx_status, frame_length)); | 1163 | rx_status, frame_length)); | |
1164 | 1164 | |||
1165 | 1165 | |||
1166 | m = dme_alloc_receive_buffer(ifp, frame_length); | 1166 | m = dme_alloc_receive_buffer(ifp, frame_length); | |
1167 | if (m == NULL) { | 1167 | if (m == NULL) { | |
1168 | /* | 1168 | /* | |
1169 | * didn't get a receive buffer, so we read the rest of the | 1169 | * didn't get a receive buffer, so we read the rest of the | |
1170 | * packet, throw it away and return an error | 1170 | * packet, throw it away and return an error | |
1171 | */ | 1171 | */ | |
1172 | for (i = 0; i < frame_length; i++ ) { | 1172 | for (i = 0; i < frame_length; i++ ) { | |
1173 | data = bus_space_read_2(sc->sc_iot, | 1173 | data = bus_space_read_2(sc->sc_iot, | |
1174 | sc->sc_ioh, sc->dme_data); | 1174 | sc->sc_ioh, sc->dme_data); | |
1175 | } | 1175 | } | |
1176 | *outBuf = NULL; | 1176 | *outBuf = NULL; | |
1177 | return 0; | 1177 | return 0; | |
1178 | } | 1178 | } | |
1179 | 1179 | |||
1180 | buf = mtod(m, uint8_t *); | 1180 | buf = mtod(m, uint8_t *); | |
1181 | 1181 | |||
1182 | RX_DPRINTF(("dme_receive: ")); | 1182 | RX_DPRINTF(("dme_receive: ")); | |
1183 | 1183 | |||
1184 | for (i = 0; i< frame_length; i += 1 ) { | 1184 | for (i = 0; i< frame_length; i += 1 ) { | |
1185 | data = bus_space_read_1(sc->sc_iot, sc->sc_ioh, sc->dme_data); | 1185 | data = bus_space_read_1(sc->sc_iot, sc->sc_ioh, sc->dme_data); | |
1186 | *buf = data; | 1186 | *buf = data; | |
1187 | buf++; | 1187 | buf++; | |
1188 | RX_DATA_DPRINTF(("%02X ", data)); | 1188 | RX_DATA_DPRINTF(("%02X ", data)); | |
1189 | } | 1189 | } | |
1190 | 1190 | |||
1191 | RX_DATA_DPRINTF(("\n")); | 1191 | RX_DATA_DPRINTF(("\n")); | |
1192 | RX_DPRINTF(("Read %d bytes\n", i)); | 1192 | RX_DPRINTF(("Read %d bytes\n", i)); | |
1193 | 1193 | |||
1194 | *outBuf = m; | 1194 | *outBuf = m; | |
1195 | return rx_status; | 1195 | return rx_status; | |
1196 | } | 1196 | } | |
1197 | 1197 | |||
1198 | struct mbuf* | 1198 | struct mbuf* | |
1199 | dme_alloc_receive_buffer(struct ifnet *ifp, unsigned int frame_length) | 1199 | dme_alloc_receive_buffer(struct ifnet *ifp, unsigned int frame_length) | |
1200 | { | 1200 | { | |
1201 | struct dme_softc *sc = ifp->if_softc; | 1201 | struct dme_softc *sc = ifp->if_softc; | |
1202 | struct mbuf *m; | 1202 | struct mbuf *m; | |
1203 | int pad; | 1203 | int pad; | |
1204 | 1204 | |||
1205 | MGETHDR(m, M_DONTWAIT, MT_DATA); | 1205 | MGETHDR(m, M_DONTWAIT, MT_DATA); | |
1206 | if (m == NULL) return NULL; | 1206 | if (m == NULL) return NULL; | |
1207 | 1207 | |||
1208 | m_set_rcvif(m, ifp); | 1208 | m_set_rcvif(m, ifp); | |
1209 | /* Ensure that we always allocate an even number of | 1209 | /* Ensure that we always allocate an even number of | |
1210 | * bytes in order to avoid writing beyond the buffer | 1210 | * bytes in order to avoid writing beyond the buffer | |
1211 | */ | 1211 | */ | |
1212 | m->m_pkthdr.len = frame_length + (frame_length % sc->sc_data_width); | 1212 | m->m_pkthdr.len = frame_length + (frame_length % sc->sc_data_width); | |
1213 | pad = ALIGN(sizeof(struct ether_header)) - | 1213 | pad = ALIGN(sizeof(struct ether_header)) - | |
1214 | sizeof(struct ether_header); | 1214 | sizeof(struct ether_header); | |
1215 | /* All our frames have the CRC attached */ | 1215 | /* All our frames have the CRC attached */ | |
1216 | m->m_flags |= M_HASFCS; | 1216 | m->m_flags |= M_HASFCS; | |
1217 | if (m->m_pkthdr.len + pad > MHLEN) { | 1217 | if (m->m_pkthdr.len + pad > MHLEN) { | |
1218 | MCLGET(m, M_DONTWAIT); | 1218 | MCLGET(m, M_DONTWAIT); | |
1219 | if ((m->m_flags & M_EXT) == 0) { | 1219 | if ((m->m_flags & M_EXT) == 0) { | |
1220 | m_freem(m); | 1220 | m_freem(m); | |
1221 | return NULL; | 1221 | return NULL; | |
1222 | } | 1222 | } | |
1223 | } | 1223 | } | |
1224 | 1224 | |||
1225 | m->m_data += pad; | 1225 | m->m_data += pad; | |
1226 | m->m_len = frame_length + (frame_length % sc->sc_data_width); | 1226 | m->m_len = frame_length + (frame_length % sc->sc_data_width); | |
1227 | 1227 | |||
1228 | return m; | 1228 | return m; | |
1229 | } | 1229 | } |
--- src/sys/dev/ic/dp8390.c 2019/05/29 10:07:29 1.95
+++ src/sys/dev/ic/dp8390.c 2020/01/29 14:14:55 1.96
@@ -1,1227 +1,1231 @@ | @@ -1,1227 +1,1231 @@ | |||
1 | /* $NetBSD: dp8390.c,v 1.95 2019/05/29 10:07:29 msaitoh Exp $ */ | 1 | /* $NetBSD: dp8390.c,v 1.96 2020/01/29 14:14:55 thorpej Exp $ */ | |
2 | 2 | |||
3 | /* | 3 | /* | |
4 | * Device driver for National Semiconductor DS8390/WD83C690 based ethernet | 4 | * Device driver for National Semiconductor DS8390/WD83C690 based ethernet | |
5 | * adapters. | 5 | * adapters. | |
6 | * | 6 | * | |
7 | * Copyright (c) 1994, 1995 Charles M. Hannum. All rights reserved. | 7 | * Copyright (c) 1994, 1995 Charles M. Hannum. All rights reserved. | |
8 | * | 8 | * | |
9 | * Copyright (C) 1993, David Greenman. This software may be used, modified, | 9 | * Copyright (C) 1993, David Greenman. This software may be used, modified, | |
10 | * copied, distributed, and sold, in both source and binary form provided that | 10 | * copied, distributed, and sold, in both source and binary form provided that | |
11 | * the above copyright and these terms are retained. Under no circumstances is | 11 | * the above copyright and these terms are retained. Under no circumstances is | |
12 | * the author responsible for the proper functioning of this software, nor does | 12 | * the author responsible for the proper functioning of this software, nor does | |
13 | * the author assume any responsibility for damages incurred with its use. | 13 | * the author assume any responsibility for damages incurred with its use. | |
14 | */ | 14 | */ | |
15 | 15 | |||
16 | #include <sys/cdefs.h> | 16 | #include <sys/cdefs.h> | |
17 | __KERNEL_RCSID(0, "$NetBSD: dp8390.c,v 1.95 2019/05/29 10:07:29 msaitoh Exp $"); | 17 | __KERNEL_RCSID(0, "$NetBSD: dp8390.c,v 1.96 2020/01/29 14:14:55 thorpej Exp $"); | |
18 | 18 | |||
19 | #include "opt_inet.h" | 19 | #include "opt_inet.h" | |
20 | 20 | |||
21 | #include <sys/param.h> | 21 | #include <sys/param.h> | |
22 | #include <sys/systm.h> | 22 | #include <sys/systm.h> | |
23 | #include <sys/device.h> | 23 | #include <sys/device.h> | |
24 | #include <sys/errno.h> | 24 | #include <sys/errno.h> | |
25 | #include <sys/ioctl.h> | 25 | #include <sys/ioctl.h> | |
26 | #include <sys/mbuf.h> | 26 | #include <sys/mbuf.h> | |
27 | #include <sys/socket.h> | 27 | #include <sys/socket.h> | |
28 | #include <sys/syslog.h> | 28 | #include <sys/syslog.h> | |
29 | #include <sys/rndsource.h> | 29 | #include <sys/rndsource.h> | |
30 | #include <sys/bus.h> | 30 | #include <sys/bus.h> | |
31 | 31 | |||
32 | #include <net/if.h> | 32 | #include <net/if.h> | |
33 | #include <net/if_dl.h> | 33 | #include <net/if_dl.h> | |
34 | #include <net/if_types.h> | 34 | #include <net/if_types.h> | |
35 | #include <net/if_media.h> | 35 | #include <net/if_media.h> | |
36 | #include <net/if_ether.h> | 36 | #include <net/if_ether.h> | |
37 | #include <net/bpf.h> | 37 | #include <net/bpf.h> | |
38 | 38 | |||
39 | #ifdef INET | 39 | #ifdef INET | |
40 | #include <netinet/in.h> | 40 | #include <netinet/in.h> | |
41 | #include <netinet/in_systm.h> | 41 | #include <netinet/in_systm.h> | |
42 | #include <netinet/in_var.h> | 42 | #include <netinet/in_var.h> | |
43 | #include <netinet/ip.h> | 43 | #include <netinet/ip.h> | |
44 | #include <netinet/if_inarp.h> | 44 | #include <netinet/if_inarp.h> | |
45 | #endif | 45 | #endif | |
46 | 46 | |||
47 | #include <dev/ic/dp8390reg.h> | 47 | #include <dev/ic/dp8390reg.h> | |
48 | #include <dev/ic/dp8390var.h> | 48 | #include <dev/ic/dp8390var.h> | |
49 | 49 | |||
50 | #ifdef DEBUG | 50 | #ifdef DEBUG | |
51 | int dp8390_debug = 0; | 51 | int dp8390_debug = 0; | |
52 | #endif | 52 | #endif | |
53 | 53 | |||
54 | static void dp8390_xmit(struct dp8390_softc *); | 54 | static void dp8390_xmit(struct dp8390_softc *); | |
55 | 55 | |||
56 | static void dp8390_read_hdr(struct dp8390_softc *, int, struct dp8390_ring *); | 56 | static void dp8390_read_hdr(struct dp8390_softc *, int, struct dp8390_ring *); | |
57 | static int dp8390_ring_copy(struct dp8390_softc *, int, void *, u_short); | 57 | static int dp8390_ring_copy(struct dp8390_softc *, int, void *, u_short); | |
58 | static int dp8390_write_mbuf(struct dp8390_softc *, struct mbuf *, int); | 58 | static int dp8390_write_mbuf(struct dp8390_softc *, struct mbuf *, int); | |
59 | 59 | |||
60 | static int dp8390_test_mem(struct dp8390_softc *); | 60 | static int dp8390_test_mem(struct dp8390_softc *); | |
61 | 61 | |||
62 | /* | 62 | /* | |
63 | * Standard media init routine for the dp8390. | 63 | * Standard media init routine for the dp8390. | |
64 | */ | 64 | */ | |
65 | void | 65 | void | |
66 | dp8390_media_init(struct dp8390_softc *sc) | 66 | dp8390_media_init(struct dp8390_softc *sc) | |
67 | { | 67 | { | |
68 | 68 | |||
69 | sc->sc_ec.ec_ifmedia = &sc->sc_media; | 69 | sc->sc_ec.ec_ifmedia = &sc->sc_media; | |
70 | ifmedia_init(&sc->sc_media, 0, dp8390_mediachange, dp8390_mediastatus); | 70 | ifmedia_init(&sc->sc_media, 0, dp8390_mediachange, dp8390_mediastatus); | |
71 | ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_MANUAL, 0, NULL); | 71 | ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_MANUAL, 0, NULL); | |
72 | ifmedia_set(&sc->sc_media, IFM_ETHER | IFM_MANUAL); | 72 | ifmedia_set(&sc->sc_media, IFM_ETHER | IFM_MANUAL); | |
73 | } | 73 | } | |
74 | 74 | |||
75 | /* | 75 | /* | |
76 | * Do bus-independent setup. | 76 | * Do bus-independent setup. | |
77 | */ | 77 | */ | |
78 | int | 78 | int | |
79 | dp8390_config(struct dp8390_softc *sc) | 79 | dp8390_config(struct dp8390_softc *sc) | |
80 | { | 80 | { | |
81 | struct ifnet *ifp = &sc->sc_ec.ec_if; | 81 | struct ifnet *ifp = &sc->sc_ec.ec_if; | |
82 | int rv; | 82 | int rv; | |
83 | 83 | |||
84 | rv = 1; | 84 | rv = 1; | |
85 | 85 | |||
86 | if (sc->test_mem == NULL) | 86 | if (sc->test_mem == NULL) | |
87 | sc->test_mem = dp8390_test_mem; | 87 | sc->test_mem = dp8390_test_mem; | |
88 | if (sc->read_hdr == NULL) | 88 | if (sc->read_hdr == NULL) | |
89 | sc->read_hdr = dp8390_read_hdr; | 89 | sc->read_hdr = dp8390_read_hdr; | |
90 | if (sc->recv_int == NULL) | 90 | if (sc->recv_int == NULL) | |
91 | sc->recv_int = dp8390_rint; | 91 | sc->recv_int = dp8390_rint; | |
92 | if (sc->ring_copy == NULL) | 92 | if (sc->ring_copy == NULL) | |
93 | sc->ring_copy = dp8390_ring_copy; | 93 | sc->ring_copy = dp8390_ring_copy; | |
94 | if (sc->write_mbuf == NULL) | 94 | if (sc->write_mbuf == NULL) | |
95 | sc->write_mbuf = dp8390_write_mbuf; | 95 | sc->write_mbuf = dp8390_write_mbuf; | |
96 | 96 | |||
97 | /* Allocate one xmit buffer if < 16k, two buffers otherwise. */ | 97 | /* Allocate one xmit buffer if < 16k, two buffers otherwise. */ | |
98 | if ((sc->mem_size < 16384) || | 98 | if ((sc->mem_size < 16384) || | |
99 | (sc->sc_flags & DP8390_NO_MULTI_BUFFERING)) | 99 | (sc->sc_flags & DP8390_NO_MULTI_BUFFERING)) | |
100 | sc->txb_cnt = 1; | 100 | sc->txb_cnt = 1; | |
101 | else if (sc->mem_size < 8192 * 3) | 101 | else if (sc->mem_size < 8192 * 3) | |
102 | sc->txb_cnt = 2; | 102 | sc->txb_cnt = 2; | |
103 | else | 103 | else | |
104 | sc->txb_cnt = 3; | 104 | sc->txb_cnt = 3; | |
105 | 105 | |||
106 | sc->tx_page_start = sc->mem_start >> ED_PAGE_SHIFT; | 106 | sc->tx_page_start = sc->mem_start >> ED_PAGE_SHIFT; | |
107 | sc->rec_page_start = sc->tx_page_start + sc->txb_cnt * ED_TXBUF_SIZE; | 107 | sc->rec_page_start = sc->tx_page_start + sc->txb_cnt * ED_TXBUF_SIZE; | |
108 | sc->rec_page_stop = sc->tx_page_start + (sc->mem_size >> ED_PAGE_SHIFT); | 108 | sc->rec_page_stop = sc->tx_page_start + (sc->mem_size >> ED_PAGE_SHIFT); | |
109 | sc->mem_ring = sc->mem_start + | 109 | sc->mem_ring = sc->mem_start + | |
110 | ((sc->txb_cnt * ED_TXBUF_SIZE) << ED_PAGE_SHIFT); | 110 | ((sc->txb_cnt * ED_TXBUF_SIZE) << ED_PAGE_SHIFT); | |
111 | sc->mem_end = sc->mem_start + sc->mem_size; | 111 | sc->mem_end = sc->mem_start + sc->mem_size; | |
112 | 112 | |||
113 | /* Now zero memory and verify that it is clear. */ | 113 | /* Now zero memory and verify that it is clear. */ | |
114 | if ((*sc->test_mem)(sc)) | 114 | if ((*sc->test_mem)(sc)) | |
115 | goto out; | 115 | goto out; | |
116 | 116 | |||
117 | /* Set interface to stopped condition (reset). */ | 117 | /* Set interface to stopped condition (reset). */ | |
118 | dp8390_stop(sc); | 118 | dp8390_stop(sc); | |
119 | 119 | |||
120 | /* Initialize ifnet structure. */ | 120 | /* Initialize ifnet structure. */ | |
121 | strcpy(ifp->if_xname, device_xname(sc->sc_dev)); | 121 | strcpy(ifp->if_xname, device_xname(sc->sc_dev)); | |
122 | ifp->if_softc = sc; | 122 | ifp->if_softc = sc; | |
123 | ifp->if_start = dp8390_start; | 123 | ifp->if_start = dp8390_start; | |
124 | ifp->if_ioctl = dp8390_ioctl; | 124 | ifp->if_ioctl = dp8390_ioctl; | |
125 | if (ifp->if_watchdog == NULL) | 125 | if (ifp->if_watchdog == NULL) | |
126 | ifp->if_watchdog = dp8390_watchdog; | 126 | ifp->if_watchdog = dp8390_watchdog; | |
127 | ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; | 127 | ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; | |
128 | IFQ_SET_READY(&ifp->if_snd); | 128 | IFQ_SET_READY(&ifp->if_snd); | |
129 | 129 | |||
130 | /* Print additional info when attached. */ | 130 | /* Print additional info when attached. */ | |
131 | aprint_normal_dev(sc->sc_dev, "Ethernet address %s\n", | 131 | aprint_normal_dev(sc->sc_dev, "Ethernet address %s\n", | |
132 | ether_sprintf(sc->sc_enaddr)); | 132 | ether_sprintf(sc->sc_enaddr)); | |
133 | 133 | |||
134 | /* Initialize media goo. */ | 134 | /* Initialize media goo. */ | |
135 | (*sc->sc_media_init)(sc); | 135 | (*sc->sc_media_init)(sc); | |
136 | 136 | |||
137 | /* We can support 802.1Q VLAN-sized frames. */ | 137 | /* We can support 802.1Q VLAN-sized frames. */ | |
138 | sc->sc_ec.ec_capabilities |= ETHERCAP_VLAN_MTU; | 138 | sc->sc_ec.ec_capabilities |= ETHERCAP_VLAN_MTU; | |
139 | 139 | |||
140 | /* Attach the interface. */ | 140 | /* Attach the interface. */ | |
141 | if_attach(ifp); | 141 | if_attach(ifp); | |
142 | if_deferred_start_init(ifp, NULL); | 142 | if_deferred_start_init(ifp, NULL); | |
143 | ether_ifattach(ifp, sc->sc_enaddr); | 143 | ether_ifattach(ifp, sc->sc_enaddr); | |
144 | 144 | |||
145 | rnd_attach_source(&sc->rnd_source, device_xname(sc->sc_dev), | 145 | rnd_attach_source(&sc->rnd_source, device_xname(sc->sc_dev), | |
146 | RND_TYPE_NET, RND_FLAG_DEFAULT); | 146 | RND_TYPE_NET, RND_FLAG_DEFAULT); | |
147 | 147 | |||
148 | /* The attach is successful. */ | 148 | /* The attach is successful. */ | |
149 | sc->sc_flags |= DP8390_ATTACHED; | 149 | sc->sc_flags |= DP8390_ATTACHED; | |
150 | 150 | |||
151 | rv = 0; | 151 | rv = 0; | |
152 | out: | 152 | out: | |
153 | return rv; | 153 | return rv; | |
154 | } | 154 | } | |
155 | 155 | |||
156 | /* | 156 | /* | |
157 | * Media change callback. | 157 | * Media change callback. | |
158 | */ | 158 | */ | |
159 | int | 159 | int | |
160 | dp8390_mediachange(struct ifnet *ifp) | 160 | dp8390_mediachange(struct ifnet *ifp) | |
161 | { | 161 | { | |
162 | struct dp8390_softc *sc = ifp->if_softc; | 162 | struct dp8390_softc *sc = ifp->if_softc; | |
163 | 163 | |||
164 | if (sc->sc_mediachange) | 164 | if (sc->sc_mediachange) | |
165 | return (*sc->sc_mediachange)(sc); | 165 | return (*sc->sc_mediachange)(sc); | |
166 | return 0; | 166 | return 0; | |
167 | } | 167 | } | |
168 | 168 | |||
169 | /* | 169 | /* | |
170 | * Media status callback. | 170 | * Media status callback. | |
171 | */ | 171 | */ | |
172 | void | 172 | void | |
173 | dp8390_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr) | 173 | dp8390_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr) | |
174 | { | 174 | { | |
175 | struct dp8390_softc *sc = ifp->if_softc; | 175 | struct dp8390_softc *sc = ifp->if_softc; | |
176 | 176 | |||
177 | if (sc->sc_enabled == 0) { | 177 | if (sc->sc_enabled == 0) { | |
178 | ifmr->ifm_active = IFM_ETHER | IFM_NONE; | 178 | ifmr->ifm_active = IFM_ETHER | IFM_NONE; | |
179 | ifmr->ifm_status = 0; | 179 | ifmr->ifm_status = 0; | |
180 | return; | 180 | return; | |
181 | } | 181 | } | |
182 | 182 | |||
183 | if (sc->sc_mediastatus) | 183 | if (sc->sc_mediastatus) | |
184 | (*sc->sc_mediastatus)(sc, ifmr); | 184 | (*sc->sc_mediastatus)(sc, ifmr); | |
185 | } | 185 | } | |
186 | 186 | |||
187 | /* | 187 | /* | |
188 | * Reset interface. | 188 | * Reset interface. | |
189 | */ | 189 | */ | |
190 | void | 190 | void | |
191 | dp8390_reset(struct dp8390_softc *sc) | 191 | dp8390_reset(struct dp8390_softc *sc) | |
192 | { | 192 | { | |
193 | int s; | 193 | int s; | |
194 | 194 | |||
195 | s = splnet(); | 195 | s = splnet(); | |
196 | dp8390_stop(sc); | 196 | dp8390_stop(sc); | |
197 | dp8390_init(sc); | 197 | dp8390_init(sc); | |
198 | splx(s); | 198 | splx(s); | |
199 | } | 199 | } | |
200 | 200 | |||
201 | /* | 201 | /* | |
202 | * Take interface offline. | 202 | * Take interface offline. | |
203 | */ | 203 | */ | |
204 | void | 204 | void | |
205 | dp8390_stop(struct dp8390_softc *sc) | 205 | dp8390_stop(struct dp8390_softc *sc) | |
206 | { | 206 | { | |
207 | bus_space_tag_t regt = sc->sc_regt; | 207 | bus_space_tag_t regt = sc->sc_regt; | |
208 | bus_space_handle_t regh = sc->sc_regh; | 208 | bus_space_handle_t regh = sc->sc_regh; | |
209 | int n = 5000; | 209 | int n = 5000; | |
210 | 210 | |||
211 | /* Stop everything on the interface, and select page 0 registers. */ | 211 | /* Stop everything on the interface, and select page 0 registers. */ | |
212 | NIC_BARRIER(regt, regh); | 212 | NIC_BARRIER(regt, regh); | |
213 | NIC_PUT(regt, regh, ED_P0_CR, | 213 | NIC_PUT(regt, regh, ED_P0_CR, | |
214 | sc->cr_proto | ED_CR_PAGE_0 | ED_CR_STP); | 214 | sc->cr_proto | ED_CR_PAGE_0 | ED_CR_STP); | |
215 | NIC_BARRIER(regt, regh); | 215 | NIC_BARRIER(regt, regh); | |
216 | 216 | |||
217 | /* | 217 | /* | |
218 | * Wait for interface to enter stopped state, but limit # of checks to | 218 | * Wait for interface to enter stopped state, but limit # of checks to | |
219 | * 'n' (about 5ms). It shouldn't even take 5us on modern DS8390's, but | 219 | * 'n' (about 5ms). It shouldn't even take 5us on modern DS8390's, but | |
220 | * just in case it's an old one. | 220 | * just in case it's an old one. | |
221 | */ | 221 | */ | |
222 | while (((NIC_GET(regt, regh, ED_P0_ISR) & ED_ISR_RST) == 0) && --n) | 222 | while (((NIC_GET(regt, regh, ED_P0_ISR) & ED_ISR_RST) == 0) && --n) | |
223 | DELAY(1); | 223 | DELAY(1); | |
224 | 224 | |||
225 | if (sc->stop_card != NULL) | 225 | if (sc->stop_card != NULL) | |
226 | (*sc->stop_card)(sc); | 226 | (*sc->stop_card)(sc); | |
227 | } | 227 | } | |
228 | 228 | |||
229 | /* | 229 | /* | |
230 | * Device timeout/watchdog routine. Entered if the device neglects to generate | 230 | * Device timeout/watchdog routine. Entered if the device neglects to generate | |
231 | * an interrupt after a transmit has been started on it. | 231 | * an interrupt after a transmit has been started on it. | |
232 | */ | 232 | */ | |
233 | 233 | |||
234 | void | 234 | void | |
235 | dp8390_watchdog(struct ifnet *ifp) | 235 | dp8390_watchdog(struct ifnet *ifp) | |
236 | { | 236 | { | |
237 | struct dp8390_softc *sc = ifp->if_softc; | 237 | struct dp8390_softc *sc = ifp->if_softc; | |
238 | 238 | |||
239 | log(LOG_ERR, "%s: device timeout\n", device_xname(sc->sc_dev)); | 239 | log(LOG_ERR, "%s: device timeout\n", device_xname(sc->sc_dev)); | |
240 | ++sc->sc_ec.ec_if.if_oerrors; | 240 | if_statinc(ifp, if_oerrors); | |
241 | 241 | |||
242 | dp8390_reset(sc); | 242 | dp8390_reset(sc); | |
243 | } | 243 | } | |
244 | 244 | |||
245 | /* | 245 | /* | |
246 | * Initialize device. | 246 | * Initialize device. | |
247 | */ | 247 | */ | |
248 | void | 248 | void | |
249 | dp8390_init(struct dp8390_softc *sc) | 249 | dp8390_init(struct dp8390_softc *sc) | |
250 | { | 250 | { | |
251 | bus_space_tag_t regt = sc->sc_regt; | 251 | bus_space_tag_t regt = sc->sc_regt; | |
252 | bus_space_handle_t regh = sc->sc_regh; | 252 | bus_space_handle_t regh = sc->sc_regh; | |
253 | struct ifnet *ifp = &sc->sc_ec.ec_if; | 253 | struct ifnet *ifp = &sc->sc_ec.ec_if; | |
254 | uint8_t mcaf[8]; | 254 | uint8_t mcaf[8]; | |
255 | int i; | 255 | int i; | |
256 | 256 | |||
257 | /* | 257 | /* | |
258 | * Initialize the NIC in the exact order outlined in the NS manual. | 258 | * Initialize the NIC in the exact order outlined in the NS manual. | |
259 | * This init procedure is "mandatory"...don't change what or when | 259 | * This init procedure is "mandatory"...don't change what or when | |
260 | * things happen. | 260 | * things happen. | |
261 | */ | 261 | */ | |
262 | 262 | |||
263 | /* Reset transmitter flags. */ | 263 | /* Reset transmitter flags. */ | |
264 | ifp->if_timer = 0; | 264 | ifp->if_timer = 0; | |
265 | 265 | |||
266 | sc->txb_inuse = 0; | 266 | sc->txb_inuse = 0; | |
267 | sc->txb_new = 0; | 267 | sc->txb_new = 0; | |
268 | sc->txb_next_tx = 0; | 268 | sc->txb_next_tx = 0; | |
269 | 269 | |||
270 | /* Set interface for page 0, remote DMA complete, stopped. */ | 270 | /* Set interface for page 0, remote DMA complete, stopped. */ | |
271 | NIC_BARRIER(regt, regh); | 271 | NIC_BARRIER(regt, regh); | |
272 | NIC_PUT(regt, regh, ED_P0_CR, | 272 | NIC_PUT(regt, regh, ED_P0_CR, | |
273 | sc->cr_proto | ED_CR_PAGE_0 | ED_CR_STP); | 273 | sc->cr_proto | ED_CR_PAGE_0 | ED_CR_STP); | |
274 | NIC_BARRIER(regt, regh); | 274 | NIC_BARRIER(regt, regh); | |
275 | 275 | |||
276 | if (sc->dcr_reg & ED_DCR_LS) { | 276 | if (sc->dcr_reg & ED_DCR_LS) { | |
277 | NIC_PUT(regt, regh, ED_P0_DCR, sc->dcr_reg); | 277 | NIC_PUT(regt, regh, ED_P0_DCR, sc->dcr_reg); | |
278 | } else { | 278 | } else { | |
279 | /* | 279 | /* | |
280 | * Set FIFO threshold to 8, No auto-init Remote DMA, byte | 280 | * Set FIFO threshold to 8, No auto-init Remote DMA, byte | |
281 | * order=80x86, byte-wide DMA xfers, | 281 | * order=80x86, byte-wide DMA xfers, | |
282 | */ | 282 | */ | |
283 | NIC_PUT(regt, regh, ED_P0_DCR, ED_DCR_FT1 | ED_DCR_LS); | 283 | NIC_PUT(regt, regh, ED_P0_DCR, ED_DCR_FT1 | ED_DCR_LS); | |
284 | } | 284 | } | |
285 | 285 | |||
286 | /* Clear remote byte count registers. */ | 286 | /* Clear remote byte count registers. */ | |
287 | NIC_PUT(regt, regh, ED_P0_RBCR0, 0); | 287 | NIC_PUT(regt, regh, ED_P0_RBCR0, 0); | |
288 | NIC_PUT(regt, regh, ED_P0_RBCR1, 0); | 288 | NIC_PUT(regt, regh, ED_P0_RBCR1, 0); | |
289 | 289 | |||
290 | /* Tell RCR to do nothing for now. */ | 290 | /* Tell RCR to do nothing for now. */ | |
291 | NIC_PUT(regt, regh, ED_P0_RCR, ED_RCR_MON | sc->rcr_proto); | 291 | NIC_PUT(regt, regh, ED_P0_RCR, ED_RCR_MON | sc->rcr_proto); | |
292 | 292 | |||
293 | /* Place NIC in internal loopback mode. */ | 293 | /* Place NIC in internal loopback mode. */ | |
294 | NIC_PUT(regt, regh, ED_P0_TCR, ED_TCR_LB0); | 294 | NIC_PUT(regt, regh, ED_P0_TCR, ED_TCR_LB0); | |
295 | 295 | |||
296 | /* Set lower bits of byte addressable framing to 0. */ | 296 | /* Set lower bits of byte addressable framing to 0. */ | |
297 | if (sc->is790) | 297 | if (sc->is790) | |
298 | NIC_PUT(regt, regh, 0x09, 0); | 298 | NIC_PUT(regt, regh, 0x09, 0); | |
299 | 299 | |||
300 | /* Initialize receive buffer ring. */ | 300 | /* Initialize receive buffer ring. */ | |
301 | NIC_PUT(regt, regh, ED_P0_BNRY, sc->rec_page_start); | 301 | NIC_PUT(regt, regh, ED_P0_BNRY, sc->rec_page_start); | |
302 | NIC_PUT(regt, regh, ED_P0_PSTART, sc->rec_page_start); | 302 | NIC_PUT(regt, regh, ED_P0_PSTART, sc->rec_page_start); | |
303 | NIC_PUT(regt, regh, ED_P0_PSTOP, sc->rec_page_stop); | 303 | NIC_PUT(regt, regh, ED_P0_PSTOP, sc->rec_page_stop); | |
304 | 304 | |||
305 | /* | 305 | /* | |
306 | * Enable the following interrupts: receive/transmit complete, | 306 | * Enable the following interrupts: receive/transmit complete, | |
307 | * receive/transmit error, and Receiver OverWrite. | 307 | * receive/transmit error, and Receiver OverWrite. | |
308 | * | 308 | * | |
309 | * Counter overflow and Remote DMA complete are *not* enabled. | 309 | * Counter overflow and Remote DMA complete are *not* enabled. | |
310 | */ | 310 | */ | |
311 | NIC_PUT(regt, regh, ED_P0_IMR, | 311 | NIC_PUT(regt, regh, ED_P0_IMR, | |
312 | ED_IMR_PRXE | ED_IMR_PTXE | ED_IMR_RXEE | ED_IMR_TXEE | | 312 | ED_IMR_PRXE | ED_IMR_PTXE | ED_IMR_RXEE | ED_IMR_TXEE | | |
313 | ED_IMR_OVWE); | 313 | ED_IMR_OVWE); | |
314 | 314 | |||
315 | /* | 315 | /* | |
316 | * Clear all interrupts. A '1' in each bit position clears the | 316 | * Clear all interrupts. A '1' in each bit position clears the | |
317 | * corresponding flag. | 317 | * corresponding flag. | |
318 | */ | 318 | */ | |
319 | NIC_PUT(regt, regh, ED_P0_ISR, 0xff); | 319 | NIC_PUT(regt, regh, ED_P0_ISR, 0xff); | |
320 | 320 | |||
321 | /* Program command register for page 1. */ | 321 | /* Program command register for page 1. */ | |
322 | NIC_BARRIER(regt, regh); | 322 | NIC_BARRIER(regt, regh); | |
323 | NIC_PUT(regt, regh, ED_P0_CR, | 323 | NIC_PUT(regt, regh, ED_P0_CR, | |
324 | sc->cr_proto | ED_CR_PAGE_1 | ED_CR_STP); | 324 | sc->cr_proto | ED_CR_PAGE_1 | ED_CR_STP); | |
325 | NIC_BARRIER(regt, regh); | 325 | NIC_BARRIER(regt, regh); | |
326 | 326 | |||
327 | /* Copy out our station address. */ | 327 | /* Copy out our station address. */ | |
328 | for (i = 0; i < ETHER_ADDR_LEN; i++) | 328 | for (i = 0; i < ETHER_ADDR_LEN; i++) | |
329 | NIC_PUT(regt, regh, ED_P1_PAR0 + i, CLLADDR(ifp->if_sadl)[i]); | 329 | NIC_PUT(regt, regh, ED_P1_PAR0 + i, CLLADDR(ifp->if_sadl)[i]); | |
330 | 330 | |||
331 | /* Set multicast filter on chip. */ | 331 | /* Set multicast filter on chip. */ | |
332 | dp8390_getmcaf(&sc->sc_ec, mcaf); | 332 | dp8390_getmcaf(&sc->sc_ec, mcaf); | |
333 | for (i = 0; i < 8; i++) | 333 | for (i = 0; i < 8; i++) | |
334 | NIC_PUT(regt, regh, ED_P1_MAR0 + i, mcaf[i]); | 334 | NIC_PUT(regt, regh, ED_P1_MAR0 + i, mcaf[i]); | |
335 | 335 | |||
336 | /* | 336 | /* | |
337 | * Set current page pointer to one page after the boundary pointer, as | 337 | * Set current page pointer to one page after the boundary pointer, as | |
338 | * recommended in the National manual. | 338 | * recommended in the National manual. | |
339 | */ | 339 | */ | |
340 | sc->next_packet = sc->rec_page_start + 1; | 340 | sc->next_packet = sc->rec_page_start + 1; | |
341 | NIC_PUT(regt, regh, ED_P1_CURR, sc->next_packet); | 341 | NIC_PUT(regt, regh, ED_P1_CURR, sc->next_packet); | |
342 | 342 | |||
343 | /* Program command register for page 0. */ | 343 | /* Program command register for page 0. */ | |
344 | NIC_BARRIER(regt, regh); | 344 | NIC_BARRIER(regt, regh); | |
345 | NIC_PUT(regt, regh, ED_P1_CR, | 345 | NIC_PUT(regt, regh, ED_P1_CR, | |
346 | sc->cr_proto | ED_CR_PAGE_0 | ED_CR_STP); | 346 | sc->cr_proto | ED_CR_PAGE_0 | ED_CR_STP); | |
347 | NIC_BARRIER(regt, regh); | 347 | NIC_BARRIER(regt, regh); | |
348 | 348 | |||
349 | /* Accept broadcast and multicast packets by default. */ | 349 | /* Accept broadcast and multicast packets by default. */ | |
350 | i = ED_RCR_AB | ED_RCR_AM | sc->rcr_proto; | 350 | i = ED_RCR_AB | ED_RCR_AM | sc->rcr_proto; | |
351 | if (ifp->if_flags & IFF_PROMISC) { | 351 | if (ifp->if_flags & IFF_PROMISC) { | |
352 | /* | 352 | /* | |
353 | * Set promiscuous mode. Multicast filter was set earlier so | 353 | * Set promiscuous mode. Multicast filter was set earlier so | |
354 | * that we should receive all multicast packets. | 354 | * that we should receive all multicast packets. | |
355 | */ | 355 | */ | |
356 | i |= ED_RCR_PRO | ED_RCR_AR | ED_RCR_SEP; | 356 | i |= ED_RCR_PRO | ED_RCR_AR | ED_RCR_SEP; | |
357 | } | 357 | } | |
358 | NIC_PUT(regt, regh, ED_P0_RCR, i); | 358 | NIC_PUT(regt, regh, ED_P0_RCR, i); | |
359 | 359 | |||
360 | /* Take interface out of loopback. */ | 360 | /* Take interface out of loopback. */ | |
361 | NIC_PUT(regt, regh, ED_P0_TCR, 0); | 361 | NIC_PUT(regt, regh, ED_P0_TCR, 0); | |
362 | 362 | |||
363 | /* Do any card-specific initialization, if applicable. */ | 363 | /* Do any card-specific initialization, if applicable. */ | |
364 | if (sc->init_card != NULL) | 364 | if (sc->init_card != NULL) | |
365 | (*sc->init_card)(sc); | 365 | (*sc->init_card)(sc); | |
366 | 366 | |||
367 | /* Fire up the interface. */ | 367 | /* Fire up the interface. */ | |
368 | NIC_BARRIER(regt, regh); | 368 | NIC_BARRIER(regt, regh); | |
369 | NIC_PUT(regt, regh, ED_P0_CR, | 369 | NIC_PUT(regt, regh, ED_P0_CR, | |
370 | sc->cr_proto | ED_CR_PAGE_0 | ED_CR_STA); | 370 | sc->cr_proto | ED_CR_PAGE_0 | ED_CR_STA); | |
371 | 371 | |||
372 | /* Set 'running' flag, and clear output active flag. */ | 372 | /* Set 'running' flag, and clear output active flag. */ | |
373 | ifp->if_flags |= IFF_RUNNING; | 373 | ifp->if_flags |= IFF_RUNNING; | |
374 | ifp->if_flags &= ~IFF_OACTIVE; | 374 | ifp->if_flags &= ~IFF_OACTIVE; | |
375 | 375 | |||
376 | /* ...and attempt to start output. */ | 376 | /* ...and attempt to start output. */ | |
377 | dp8390_start(ifp); | 377 | dp8390_start(ifp); | |
378 | } | 378 | } | |
379 | 379 | |||
380 | /* | 380 | /* | |
381 | * This routine actually starts the transmission on the interface. | 381 | * This routine actually starts the transmission on the interface. | |
382 | */ | 382 | */ | |
383 | static void | 383 | static void | |
384 | dp8390_xmit(struct dp8390_softc *sc) | 384 | dp8390_xmit(struct dp8390_softc *sc) | |
385 | { | 385 | { | |
386 | bus_space_tag_t regt = sc->sc_regt; | 386 | bus_space_tag_t regt = sc->sc_regt; | |
387 | bus_space_handle_t regh = sc->sc_regh; | 387 | bus_space_handle_t regh = sc->sc_regh; | |
388 | struct ifnet *ifp = &sc->sc_ec.ec_if; | 388 | struct ifnet *ifp = &sc->sc_ec.ec_if; | |
389 | u_short len; | 389 | u_short len; | |
390 | 390 | |||
391 | #ifdef DIAGNOSTIC | 391 | #ifdef DIAGNOSTIC | |
392 | if ((sc->txb_next_tx + sc->txb_inuse) % sc->txb_cnt != sc->txb_new) | 392 | if ((sc->txb_next_tx + sc->txb_inuse) % sc->txb_cnt != sc->txb_new) | |
393 | panic("dp8390_xmit: desync, next_tx=%d inuse=%d cnt=%d new=%d", | 393 | panic("dp8390_xmit: desync, next_tx=%d inuse=%d cnt=%d new=%d", | |
394 | sc->txb_next_tx, sc->txb_inuse, sc->txb_cnt, sc->txb_new); | 394 | sc->txb_next_tx, sc->txb_inuse, sc->txb_cnt, sc->txb_new); | |
395 | 395 | |||
396 | if (sc->txb_inuse == 0) | 396 | if (sc->txb_inuse == 0) | |
397 | panic("dp8390_xmit: no packets to xmit"); | 397 | panic("dp8390_xmit: no packets to xmit"); | |
398 | #endif | 398 | #endif | |
399 | 399 | |||
400 | len = sc->txb_len[sc->txb_next_tx]; | 400 | len = sc->txb_len[sc->txb_next_tx]; | |
401 | 401 | |||
402 | /* Set NIC for page 0 register access. */ | 402 | /* Set NIC for page 0 register access. */ | |
403 | NIC_BARRIER(regt, regh); | 403 | NIC_BARRIER(regt, regh); | |
404 | NIC_PUT(regt, regh, ED_P0_CR, | 404 | NIC_PUT(regt, regh, ED_P0_CR, | |
405 | sc->cr_proto | ED_CR_PAGE_0 | ED_CR_STA); | 405 | sc->cr_proto | ED_CR_PAGE_0 | ED_CR_STA); | |
406 | NIC_BARRIER(regt, regh); | 406 | NIC_BARRIER(regt, regh); | |
407 | 407 | |||
408 | /* Set TX buffer start page. */ | 408 | /* Set TX buffer start page. */ | |
409 | NIC_PUT(regt, regh, ED_P0_TPSR, | 409 | NIC_PUT(regt, regh, ED_P0_TPSR, | |
410 | sc->tx_page_start + sc->txb_next_tx * ED_TXBUF_SIZE); | 410 | sc->tx_page_start + sc->txb_next_tx * ED_TXBUF_SIZE); | |
411 | 411 | |||
412 | /* Set TX length. */ | 412 | /* Set TX length. */ | |
413 | NIC_PUT(regt, regh, ED_P0_TBCR0, len); | 413 | NIC_PUT(regt, regh, ED_P0_TBCR0, len); | |
414 | NIC_PUT(regt, regh, ED_P0_TBCR1, len >> 8); | 414 | NIC_PUT(regt, regh, ED_P0_TBCR1, len >> 8); | |
415 | 415 | |||
416 | /* Set page 0, remote DMA complete, transmit packet, and *start*. */ | 416 | /* Set page 0, remote DMA complete, transmit packet, and *start*. */ | |
417 | NIC_BARRIER(regt, regh); | 417 | NIC_BARRIER(regt, regh); | |
418 | NIC_PUT(regt, regh, ED_P0_CR, | 418 | NIC_PUT(regt, regh, ED_P0_CR, | |
419 | sc->cr_proto | ED_CR_PAGE_0 | ED_CR_TXP | ED_CR_STA); | 419 | sc->cr_proto | ED_CR_PAGE_0 | ED_CR_TXP | ED_CR_STA); | |
420 | 420 | |||
421 | /* Point to next transmit buffer slot and wrap if necessary. */ | 421 | /* Point to next transmit buffer slot and wrap if necessary. */ | |
422 | if (++sc->txb_next_tx == sc->txb_cnt) | 422 | if (++sc->txb_next_tx == sc->txb_cnt) | |
423 | sc->txb_next_tx = 0; | 423 | sc->txb_next_tx = 0; | |
424 | 424 | |||
425 | /* Set a timer just in case we never hear from the board again. */ | 425 | /* Set a timer just in case we never hear from the board again. */ | |
426 | ifp->if_timer = 2; | 426 | ifp->if_timer = 2; | |
427 | } | 427 | } | |
428 | 428 | |||
429 | /* | 429 | /* | |
430 | * Start output on interface. | 430 | * Start output on interface. | |
431 | * We make two assumptions here: | 431 | * We make two assumptions here: | |
432 | * 1) that the current priority is set to splnet _before_ this code | 432 | * 1) that the current priority is set to splnet _before_ this code | |
433 | * is called *and* is returned to the appropriate priority after | 433 | * is called *and* is returned to the appropriate priority after | |
434 | * return | 434 | * return | |
435 | * 2) that the IFF_OACTIVE flag is checked before this code is called | 435 | * 2) that the IFF_OACTIVE flag is checked before this code is called | |
436 | * (i.e. that the output part of the interface is idle) | 436 | * (i.e. that the output part of the interface is idle) | |
437 | */ | 437 | */ | |
438 | void | 438 | void | |
439 | dp8390_start(struct ifnet *ifp) | 439 | dp8390_start(struct ifnet *ifp) | |
440 | { | 440 | { | |
441 | struct dp8390_softc *sc = ifp->if_softc; | 441 | struct dp8390_softc *sc = ifp->if_softc; | |
442 | struct mbuf *m0; | 442 | struct mbuf *m0; | |
443 | int buffer; | 443 | int buffer; | |
444 | int len; | 444 | int len; | |
445 | 445 | |||
446 | if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING) | 446 | if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING) | |
447 | return; | 447 | return; | |
448 | 448 | |||
449 | outloop: | 449 | outloop: | |
450 | /* See if there is room to put another packet in the buffer. */ | 450 | /* See if there is room to put another packet in the buffer. */ | |
451 | if (sc->txb_inuse == sc->txb_cnt) { | 451 | if (sc->txb_inuse == sc->txb_cnt) { | |
452 | /* No room. Indicate this to the outside world and exit. */ | 452 | /* No room. Indicate this to the outside world and exit. */ | |
453 | ifp->if_flags |= IFF_OACTIVE; | 453 | ifp->if_flags |= IFF_OACTIVE; | |
454 | return; | 454 | return; | |
455 | } | 455 | } | |
456 | IFQ_DEQUEUE(&ifp->if_snd, m0); | 456 | IFQ_DEQUEUE(&ifp->if_snd, m0); | |
457 | if (m0 == NULL) | 457 | if (m0 == NULL) | |
458 | return; | 458 | return; | |
459 | 459 | |||
460 | /* We need to use m->m_pkthdr.len, so require the header */ | 460 | /* We need to use m->m_pkthdr.len, so require the header */ | |
461 | if ((m0->m_flags & M_PKTHDR) == 0) | 461 | if ((m0->m_flags & M_PKTHDR) == 0) | |
462 | panic("dp8390_start: no header mbuf"); | 462 | panic("dp8390_start: no header mbuf"); | |
463 | 463 | |||
464 | /* Tap off here if there is a BPF listener. */ | 464 | /* Tap off here if there is a BPF listener. */ | |
465 | bpf_mtap(ifp, m0, BPF_D_OUT); | 465 | bpf_mtap(ifp, m0, BPF_D_OUT); | |
466 | 466 | |||
467 | /* txb_new points to next open buffer slot. */ | 467 | /* txb_new points to next open buffer slot. */ | |
468 | buffer = sc->mem_start + | 468 | buffer = sc->mem_start + | |
469 | ((sc->txb_new * ED_TXBUF_SIZE) << ED_PAGE_SHIFT); | 469 | ((sc->txb_new * ED_TXBUF_SIZE) << ED_PAGE_SHIFT); | |
470 | 470 | |||
471 | len = (*sc->write_mbuf)(sc, m0, buffer); | 471 | len = (*sc->write_mbuf)(sc, m0, buffer); | |
472 | 472 | |||
473 | m_freem(m0); | 473 | m_freem(m0); | |
474 | sc->txb_len[sc->txb_new] = len; | 474 | sc->txb_len[sc->txb_new] = len; | |
475 | 475 | |||
476 | /* Point to next buffer slot and wrap if necessary. */ | 476 | /* Point to next buffer slot and wrap if necessary. */ | |
477 | if (++sc->txb_new == sc->txb_cnt) | 477 | if (++sc->txb_new == sc->txb_cnt) | |
478 | sc->txb_new = 0; | 478 | sc->txb_new = 0; | |
479 | 479 | |||
480 | /* Start the first packet transmitting. */ | 480 | /* Start the first packet transmitting. */ | |
481 | if (sc->txb_inuse++ == 0) | 481 | if (sc->txb_inuse++ == 0) | |
482 | dp8390_xmit(sc); | 482 | dp8390_xmit(sc); | |
483 | 483 | |||
484 | /* Loop back to the top to possibly buffer more packets. */ | 484 | /* Loop back to the top to possibly buffer more packets. */ | |
485 | goto outloop; | 485 | goto outloop; | |
486 | } | 486 | } | |
487 | 487 | |||
488 | /* | 488 | /* | |
489 | * Ethernet interface receiver interrupt. | 489 | * Ethernet interface receiver interrupt. | |
490 | */ | 490 | */ | |
491 | void | 491 | void | |
492 | dp8390_rint(struct dp8390_softc *sc) | 492 | dp8390_rint(struct dp8390_softc *sc) | |
493 | { | 493 | { | |
494 | bus_space_tag_t regt = sc->sc_regt; | 494 | bus_space_tag_t regt = sc->sc_regt; | |
495 | bus_space_handle_t regh = sc->sc_regh; | 495 | bus_space_handle_t regh = sc->sc_regh; | |
496 | struct dp8390_ring packet_hdr; | 496 | struct dp8390_ring packet_hdr; | |
497 | int packet_ptr; | 497 | int packet_ptr; | |
498 | uint16_t len; | 498 | uint16_t len; | |
499 | uint8_t boundary, current; | 499 | uint8_t boundary, current; | |
500 | uint8_t nlen; | 500 | uint8_t nlen; | |
501 | 501 | |||
502 | loop: | 502 | loop: | |
503 | /* Set NIC to page 1 registers to get 'current' pointer. */ | 503 | /* Set NIC to page 1 registers to get 'current' pointer. */ | |
504 | NIC_BARRIER(regt, regh); | 504 | NIC_BARRIER(regt, regh); | |
505 | NIC_PUT(regt, regh, ED_P0_CR, | 505 | NIC_PUT(regt, regh, ED_P0_CR, | |
506 | sc->cr_proto | ED_CR_PAGE_1 | ED_CR_STA); | 506 | sc->cr_proto | ED_CR_PAGE_1 | ED_CR_STA); | |
507 | NIC_BARRIER(regt, regh); | 507 | NIC_BARRIER(regt, regh); | |
508 | 508 | |||
509 | /* | 509 | /* | |
510 | * 'sc->next_packet' is the logical beginning of the ring-buffer - i.e. | 510 | * 'sc->next_packet' is the logical beginning of the ring-buffer - i.e. | |
511 | * it points to where new data has been buffered. The 'CURR' (current) | 511 | * it points to where new data has been buffered. The 'CURR' (current) | |
512 | * register points to the logical end of the ring-buffer - i.e. it | 512 | * register points to the logical end of the ring-buffer - i.e. it | |
513 | * points to where additional new data will be added. We loop here | 513 | * points to where additional new data will be added. We loop here | |
514 | * until the logical beginning equals the logical end (or in other | 514 | * until the logical beginning equals the logical end (or in other | |
515 | * words, until the ring-buffer is empty). | 515 | * words, until the ring-buffer is empty). | |
516 | */ | 516 | */ | |
517 | current = NIC_GET(regt, regh, ED_P1_CURR); | 517 | current = NIC_GET(regt, regh, ED_P1_CURR); | |
518 | if (sc->next_packet == current) | 518 | if (sc->next_packet == current) | |
519 | return; | 519 | return; | |
520 | 520 | |||
521 | /* Set NIC to page 0 registers to update boundary register. */ | 521 | /* Set NIC to page 0 registers to update boundary register. */ | |
522 | NIC_BARRIER(regt, regh); | 522 | NIC_BARRIER(regt, regh); | |
523 | NIC_PUT(regt, regh, ED_P1_CR, | 523 | NIC_PUT(regt, regh, ED_P1_CR, | |
524 | sc->cr_proto | ED_CR_PAGE_0 | ED_CR_STA); | 524 | sc->cr_proto | ED_CR_PAGE_0 | ED_CR_STA); | |
525 | NIC_BARRIER(regt, regh); | 525 | NIC_BARRIER(regt, regh); | |
526 | 526 | |||
527 | do { | 527 | do { | |
528 | /* Get pointer to this buffer's header structure. */ | 528 | /* Get pointer to this buffer's header structure. */ | |
529 | packet_ptr = sc->mem_ring + | 529 | packet_ptr = sc->mem_ring + | |
530 | ((sc->next_packet - sc->rec_page_start) << ED_PAGE_SHIFT); | 530 | ((sc->next_packet - sc->rec_page_start) << ED_PAGE_SHIFT); | |
531 | 531 | |||
532 | (*sc->read_hdr)(sc, packet_ptr, &packet_hdr); | 532 | (*sc->read_hdr)(sc, packet_ptr, &packet_hdr); | |
533 | len = packet_hdr.count; | 533 | len = packet_hdr.count; | |
534 | 534 | |||
535 | /* | 535 | /* | |
536 | * Try do deal with old, buggy chips that sometimes duplicate | 536 | * Try do deal with old, buggy chips that sometimes duplicate | |
537 | * the low byte of the length into the high byte. We do this | 537 | * the low byte of the length into the high byte. We do this | |
538 | * by simply ignoring the high byte of the length and always | 538 | * by simply ignoring the high byte of the length and always | |
539 | * recalculating it. | 539 | * recalculating it. | |
540 | * | 540 | * | |
541 | * NOTE: sc->next_packet is pointing at the current packet. | 541 | * NOTE: sc->next_packet is pointing at the current packet. | |
542 | */ | 542 | */ | |
543 | if (packet_hdr.next_packet >= sc->next_packet) | 543 | if (packet_hdr.next_packet >= sc->next_packet) | |
544 | nlen = (packet_hdr.next_packet - sc->next_packet); | 544 | nlen = (packet_hdr.next_packet - sc->next_packet); | |
545 | else | 545 | else | |
546 | nlen = ((packet_hdr.next_packet - sc->rec_page_start) + | 546 | nlen = ((packet_hdr.next_packet - sc->rec_page_start) + | |
547 | (sc->rec_page_stop - sc->next_packet)); | 547 | (sc->rec_page_stop - sc->next_packet)); | |
548 | --nlen; | 548 | --nlen; | |
549 | if ((len & ED_PAGE_MASK) + sizeof(packet_hdr) > ED_PAGE_SIZE) | 549 | if ((len & ED_PAGE_MASK) + sizeof(packet_hdr) > ED_PAGE_SIZE) | |
550 | --nlen; | 550 | --nlen; | |
551 | len = (len & ED_PAGE_MASK) | (nlen << ED_PAGE_SHIFT); | 551 | len = (len & ED_PAGE_MASK) | (nlen << ED_PAGE_SHIFT); | |
552 | #ifdef DIAGNOSTIC | 552 | #ifdef DIAGNOSTIC | |
553 | if (len != packet_hdr.count) { | 553 | if (len != packet_hdr.count) { | |
554 | aprint_verbose_dev(sc->sc_dev, "length does not match " | 554 | aprint_verbose_dev(sc->sc_dev, "length does not match " | |
555 | "next packet pointer\n"); | 555 | "next packet pointer\n"); | |
556 | aprint_verbose_dev(sc->sc_dev, "len %04x nlen %04x " | 556 | aprint_verbose_dev(sc->sc_dev, "len %04x nlen %04x " | |
557 | "start %02x first %02x curr %02x next %02x " | 557 | "start %02x first %02x curr %02x next %02x " | |
558 | "stop %02x\n", packet_hdr.count, len, | 558 | "stop %02x\n", packet_hdr.count, len, | |
559 | sc->rec_page_start, sc->next_packet, current, | 559 | sc->rec_page_start, sc->next_packet, current, | |
560 | packet_hdr.next_packet, sc->rec_page_stop); | 560 | packet_hdr.next_packet, sc->rec_page_stop); | |
561 | } | 561 | } | |
562 | #endif | 562 | #endif | |
563 | 563 | |||
564 | /* | 564 | /* | |
565 | * Be fairly liberal about what we allow as a "reasonable" | 565 | * Be fairly liberal about what we allow as a "reasonable" | |
566 | * length so that a [crufty] packet will make it to BPF (and | 566 | * length so that a [crufty] packet will make it to BPF (and | |
567 | * can thus be analyzed). Note that all that is really | 567 | * can thus be analyzed). Note that all that is really | |
568 | * important is that we have a length that will fit into one | 568 | * important is that we have a length that will fit into one | |
569 | * mbuf cluster or less; the upper layer protocols can then | 569 | * mbuf cluster or less; the upper layer protocols can then | |
570 | * figure out the length from their own length field(s). | 570 | * figure out the length from their own length field(s). | |
571 | */ | 571 | */ | |
572 | if (len <= MCLBYTES && | 572 | if (len <= MCLBYTES && | |
573 | packet_hdr.next_packet >= sc->rec_page_start && | 573 | packet_hdr.next_packet >= sc->rec_page_start && | |
574 | packet_hdr.next_packet < sc->rec_page_stop) { | 574 | packet_hdr.next_packet < sc->rec_page_stop) { | |
575 | /* Go get packet. */ | 575 | /* Go get packet. */ | |
576 | dp8390_read(sc, | 576 | dp8390_read(sc, | |
577 | packet_ptr + sizeof(struct dp8390_ring), | 577 | packet_ptr + sizeof(struct dp8390_ring), | |
578 | len - sizeof(struct dp8390_ring)); | 578 | len - sizeof(struct dp8390_ring)); | |
579 | } else { | 579 | } else { | |
580 | /* Really BAD. The ring pointers are corrupted. */ | 580 | /* Really BAD. The ring pointers are corrupted. */ | |
581 | log(LOG_ERR, "%s: NIC memory corrupt - " | 581 | log(LOG_ERR, "%s: NIC memory corrupt - " | |
582 | "invalid packet length %d\n", | 582 | "invalid packet length %d\n", | |
583 | device_xname(sc->sc_dev), len); | 583 | device_xname(sc->sc_dev), len); | |
584 | ++sc->sc_ec.ec_if.if_ierrors; | 584 | if_statinc(&sc->sc_ec.ec_if, if_ierrors); | |
585 | dp8390_reset(sc); | 585 | dp8390_reset(sc); | |
586 | return; | 586 | return; | |
587 | } | 587 | } | |
588 | 588 | |||
589 | /* Update next packet pointer. */ | 589 | /* Update next packet pointer. */ | |
590 | sc->next_packet = packet_hdr.next_packet; | 590 | sc->next_packet = packet_hdr.next_packet; | |
591 | 591 | |||
592 | /* | 592 | /* | |
593 | * Update NIC boundary pointer - being careful to keep it one | 593 | * Update NIC boundary pointer - being careful to keep it one | |
594 | * buffer behind (as recommended by NS databook). | 594 | * buffer behind (as recommended by NS databook). | |
595 | */ | 595 | */ | |
596 | boundary = sc->next_packet - 1; | 596 | boundary = sc->next_packet - 1; | |
597 | if (boundary < sc->rec_page_start) | 597 | if (boundary < sc->rec_page_start) | |
598 | boundary = sc->rec_page_stop - 1; | 598 | boundary = sc->rec_page_stop - 1; | |
599 | NIC_PUT(regt, regh, ED_P0_BNRY, boundary); | 599 | NIC_PUT(regt, regh, ED_P0_BNRY, boundary); | |
600 | } while (sc->next_packet != current); | 600 | } while (sc->next_packet != current); | |
601 | 601 | |||
602 | goto loop; | 602 | goto loop; | |
603 | } | 603 | } | |
604 | 604 | |||
605 | /* Ethernet interface interrupt processor. */ | 605 | /* Ethernet interface interrupt processor. */ | |
606 | int | 606 | int | |
607 | dp8390_intr(void *arg) | 607 | dp8390_intr(void *arg) | |
608 | { | 608 | { | |
609 | struct dp8390_softc *sc = arg; | 609 | struct dp8390_softc *sc = arg; | |
610 | bus_space_tag_t regt = sc->sc_regt; | 610 | bus_space_tag_t regt = sc->sc_regt; | |
611 | bus_space_handle_t regh = sc->sc_regh; | 611 | bus_space_handle_t regh = sc->sc_regh; | |
612 | struct ifnet *ifp = &sc->sc_ec.ec_if; | 612 | struct ifnet *ifp = &sc->sc_ec.ec_if; | |
613 | uint8_t isr; | 613 | uint8_t isr; | |
614 | uint8_t rndisr; | 614 | uint8_t rndisr; | |
615 | 615 | |||
616 | if (sc->sc_enabled == 0 || !device_is_active(sc->sc_dev)) | 616 | if (sc->sc_enabled == 0 || !device_is_active(sc->sc_dev)) | |
617 | return 0; | 617 | return 0; | |
618 | 618 | |||
619 | /* Set NIC to page 0 registers. */ | 619 | /* Set NIC to page 0 registers. */ | |
620 | NIC_BARRIER(regt, regh); | 620 | NIC_BARRIER(regt, regh); | |
621 | NIC_PUT(regt, regh, ED_P0_CR, sc->cr_proto | ED_CR_PAGE_0 | ED_CR_STA); | 621 | NIC_PUT(regt, regh, ED_P0_CR, sc->cr_proto | ED_CR_PAGE_0 | ED_CR_STA); | |
622 | NIC_BARRIER(regt, regh); | 622 | NIC_BARRIER(regt, regh); | |
623 | 623 | |||
624 | isr = NIC_GET(regt, regh, ED_P0_ISR); | 624 | isr = NIC_GET(regt, regh, ED_P0_ISR); | |
625 | if (isr == 0) | 625 | if (isr == 0) | |
626 | return 0; | 626 | return 0; | |
627 | 627 | |||
628 | rndisr = isr; | 628 | rndisr = isr; | |
629 | 629 | |||
630 | /* Loop until there are no more new interrupts. */ | 630 | /* Loop until there are no more new interrupts. */ | |
631 | for (;;) { | 631 | for (;;) { | |
632 | /* | 632 | /* | |
633 | * Reset all the bits that we are 'acknowledging' by writing a | 633 | * Reset all the bits that we are 'acknowledging' by writing a | |
634 | * '1' to each bit position that was set. | 634 | * '1' to each bit position that was set. | |
635 | * (Writing a '1' *clears* the bit.) | 635 | * (Writing a '1' *clears* the bit.) | |
636 | */ | 636 | */ | |
637 | NIC_PUT(regt, regh, ED_P0_ISR, isr); | 637 | NIC_PUT(regt, regh, ED_P0_ISR, isr); | |
638 | 638 | |||
639 | /* Work around for AX88190 bug */ | 639 | /* Work around for AX88190 bug */ | |
640 | if ((sc->sc_flags & DP8390_DO_AX88190_WORKAROUND) != 0) | 640 | if ((sc->sc_flags & DP8390_DO_AX88190_WORKAROUND) != 0) | |
641 | while ((NIC_GET(regt, regh, ED_P0_ISR) & isr) != 0) { | 641 | while ((NIC_GET(regt, regh, ED_P0_ISR) & isr) != 0) { | |
642 | NIC_PUT(regt, regh, ED_P0_ISR, 0); | 642 | NIC_PUT(regt, regh, ED_P0_ISR, 0); | |
643 | NIC_PUT(regt, regh, ED_P0_ISR, isr); | 643 | NIC_PUT(regt, regh, ED_P0_ISR, isr); | |
644 | } | 644 | } | |
645 | 645 | |||
646 | /* | 646 | /* | |
647 | * Handle transmitter interrupts. Handle these first because | 647 | * Handle transmitter interrupts. Handle these first because | |
648 | * the receiver will reset the board under some conditions. | 648 | * the receiver will reset the board under some conditions. | |
649 | * | 649 | * | |
650 | * If the chip was reset while a packet was transmitting, it | 650 | * If the chip was reset while a packet was transmitting, it | |
651 | * may still deliver a TX interrupt. In this case, just ignore | 651 | * may still deliver a TX interrupt. In this case, just ignore | |
652 | * the interrupt. | 652 | * the interrupt. | |
653 | */ | 653 | */ | |
654 | if ((isr & (ED_ISR_PTX | ED_ISR_TXE)) != 0 && | 654 | if ((isr & (ED_ISR_PTX | ED_ISR_TXE)) != 0 && | |
655 | sc->txb_inuse != 0) { | 655 | sc->txb_inuse != 0) { | |
656 | net_stat_ref_t nsr = IF_STAT_GETREF(ifp); | |||
656 | uint8_t collisions = | 657 | uint8_t collisions = | |
657 | NIC_GET(regt, regh, ED_P0_NCR) & 0x0f; | 658 | NIC_GET(regt, regh, ED_P0_NCR) & 0x0f; | |
658 | 659 | |||
659 | /* | 660 | /* | |
660 | * Check for transmit error. If a TX completed with an | 661 | * Check for transmit error. If a TX completed with an | |
661 | * error, we end up throwing the packet away. Really | 662 | * error, we end up throwing the packet away. Really | |
662 | * the only error that is possible is excessive | 663 | * the only error that is possible is excessive | |
663 | * collisions, and in this case it is best to allow the | 664 | * collisions, and in this case it is best to allow the | |
664 | * automatic mechanisms of TCP to backoff the flow. Of | 665 | * automatic mechanisms of TCP to backoff the flow. Of | |
665 | * course, with UDP we're screwed, but this is expected | 666 | * course, with UDP we're screwed, but this is expected | |
666 | * when a network is heavily loaded. | 667 | * when a network is heavily loaded. | |
667 | */ | 668 | */ | |
668 | if ((isr & ED_ISR_TXE) != 0) { | 669 | if ((isr & ED_ISR_TXE) != 0) { | |
669 | /* Excessive collisions (16). */ | 670 | /* Excessive collisions (16). */ | |
670 | if ((NIC_GET(regt, regh, ED_P0_TSR) | 671 | if ((NIC_GET(regt, regh, ED_P0_TSR) | |
671 | & ED_TSR_ABT) && (collisions == 0)) { | 672 | & ED_TSR_ABT) && (collisions == 0)) { | |
672 | /* | 673 | /* | |
673 | * When collisions total 16, the P0_NCR | 674 | * When collisions total 16, the P0_NCR | |
674 | * will indicate 0, and the TSR_ABT is | 675 | * will indicate 0, and the TSR_ABT is | |
675 | * set. | 676 | * set. | |
676 | */ | 677 | */ | |
677 | collisions = 16; | 678 | collisions = 16; | |
678 | } | 679 | } | |
679 | 680 | |||
680 | /* Update output errors counter. */ | 681 | /* Update output errors counter. */ | |
681 | ++ifp->if_oerrors; | 682 | if_statinc_ref(nsr, if_oerrors); | |
682 | } else { | 683 | } else { | |
683 | /* | 684 | /* | |
684 | * Throw away the non-error status bits. | 685 | * Throw away the non-error status bits. | |
685 | * | 686 | * | |
686 | * XXX | 687 | * XXX | |
687 | * It may be useful to detect loss of carrier | 688 | * It may be useful to detect loss of carrier | |
688 | * and late collisions here. | 689 | * and late collisions here. | |
689 | */ | 690 | */ | |
690 | (void)NIC_GET(regt, regh, ED_P0_TSR); | 691 | (void)NIC_GET(regt, regh, ED_P0_TSR); | |
691 | 692 | |||
692 | /* | 693 | /* | |
693 | * Update total number of successfully | 694 | * Update total number of successfully | |
694 | * transmitted packets. | 695 | * transmitted packets. | |
695 | */ | 696 | */ | |
696 | ++ifp->if_opackets; | 697 | if_statinc_ref(nsr, if_opackets); | |
697 | } | 698 | } | |
698 | 699 | |||
699 | /* Clear watchdog timer. */ | 700 | /* Clear watchdog timer. */ | |
700 | ifp->if_timer = 0; | 701 | ifp->if_timer = 0; | |
701 | ifp->if_flags &= ~IFF_OACTIVE; | 702 | ifp->if_flags &= ~IFF_OACTIVE; | |
702 | 703 | |||
703 | /* | 704 | /* | |
704 | * Add in total number of collisions on last | 705 | * Add in total number of collisions on last | |
705 | * transmission. | 706 | * transmission. | |
706 | */ | 707 | */ | |
707 | ifp->if_collisions += collisions; | 708 | if (collisions) | |
709 | if_statadd_ref(nsr, if_collisions, collisions); | |||
710 | ||||
711 | IF_STAT_PUTREF(ifp); | |||
708 | 712 | |||
709 | /* | 713 | /* | |
710 | * Decrement buffer in-use count if not zero (can only | 714 | * Decrement buffer in-use count if not zero (can only | |
711 | * be zero if a transmitter interrupt occurred while | 715 | * be zero if a transmitter interrupt occurred while | |
712 | * not actually transmitting). | 716 | * not actually transmitting). | |
713 | * If data is ready to transmit, start it transmitting, | 717 | * If data is ready to transmit, start it transmitting, | |
714 | * otherwise defer until after handling receiver. | 718 | * otherwise defer until after handling receiver. | |
715 | */ | 719 | */ | |
716 | if (--sc->txb_inuse != 0) | 720 | if (--sc->txb_inuse != 0) | |
717 | dp8390_xmit(sc); | 721 | dp8390_xmit(sc); | |
718 | } | 722 | } | |
719 | 723 | |||
720 | /* Handle receiver interrupts. */ | 724 | /* Handle receiver interrupts. */ | |
721 | if ((isr & (ED_ISR_PRX | ED_ISR_RXE | ED_ISR_OVW)) != 0) { | 725 | if ((isr & (ED_ISR_PRX | ED_ISR_RXE | ED_ISR_OVW)) != 0) { | |
722 | /* | 726 | /* | |
723 | * Overwrite warning. In order to make sure that a | 727 | * Overwrite warning. In order to make sure that a | |
724 | * lockup of the local DMA hasn't occurred, we reset | 728 | * lockup of the local DMA hasn't occurred, we reset | |
725 | * and re-init the NIC. The NSC manual suggests only a | 729 | * and re-init the NIC. The NSC manual suggests only a | |
726 | * partial reset/re-init is necessary - but some chips | 730 | * partial reset/re-init is necessary - but some chips | |
727 | * seem to want more. The DMA lockup has been seen | 731 | * seem to want more. The DMA lockup has been seen | |
728 | * only with early rev chips - Methinks this bug was | 732 | * only with early rev chips - Methinks this bug was | |
729 | * fixed in later revs. -DG | 733 | * fixed in later revs. -DG | |
730 | */ | 734 | */ | |
731 | if ((isr & ED_ISR_OVW) != 0) { | 735 | if ((isr & ED_ISR_OVW) != 0) { | |
732 | ++ifp->if_ierrors; | 736 | if_statinc(ifp, if_ierrors); | |
733 | #ifdef DIAGNOSTIC | 737 | #ifdef DIAGNOSTIC | |
734 | log(LOG_WARNING, "%s: warning - receiver " | 738 | log(LOG_WARNING, "%s: warning - receiver " | |
735 | "ring buffer overrun\n", | 739 | "ring buffer overrun\n", | |
736 | device_xname(sc->sc_dev)); | 740 | device_xname(sc->sc_dev)); | |
737 | #endif | 741 | #endif | |
738 | /* Stop/reset/re-init NIC. */ | 742 | /* Stop/reset/re-init NIC. */ | |
739 | dp8390_reset(sc); | 743 | dp8390_reset(sc); | |
740 | } else { | 744 | } else { | |
741 | /* | 745 | /* | |
742 | * Receiver Error. One or more of: CRC error, | 746 | * Receiver Error. One or more of: CRC error, | |
743 | * frame alignment error FIFO overrun, or | 747 | * frame alignment error FIFO overrun, or | |
744 | * missed packet. | 748 | * missed packet. | |
745 | */ | 749 | */ | |
746 | if ((isr & ED_ISR_RXE) != 0) { | 750 | if ((isr & ED_ISR_RXE) != 0) { | |
747 | ++ifp->if_ierrors; | 751 | if_statinc(ifp, if_ierrors); | |
748 | #ifdef DEBUG | 752 | #ifdef DEBUG | |
749 | if (dp8390_debug) { | 753 | if (dp8390_debug) { | |
750 | printf("%s: receive error %x\n", | 754 | printf("%s: receive error %x\n", | |
751 | device_xname(sc->sc_dev), | 755 | device_xname(sc->sc_dev), | |
752 | NIC_GET(regt, regh, | 756 | NIC_GET(regt, regh, | |
753 | ED_P0_RSR)); | 757 | ED_P0_RSR)); | |
754 | } | 758 | } | |
755 | #endif | 759 | #endif | |
756 | } | 760 | } | |
757 | 761 | |||
758 | /* | 762 | /* | |
759 | * Go get the packet(s) | 763 | * Go get the packet(s) | |
760 | * XXX - Doing this on an error is dubious | 764 | * XXX - Doing this on an error is dubious | |
761 | * because there shouldn't be any data to get | 765 | * because there shouldn't be any data to get | |
762 | * (we've configured the interface to not | 766 | * (we've configured the interface to not | |
763 | * accept packets with errors). | 767 | * accept packets with errors). | |
764 | */ | 768 | */ | |
765 | (*sc->recv_int)(sc); | 769 | (*sc->recv_int)(sc); | |
766 | } | 770 | } | |
767 | } | 771 | } | |
768 | 772 | |||
769 | /* | 773 | /* | |
770 | * If it looks like the transmitter can take more data, attempt | 774 | * If it looks like the transmitter can take more data, attempt | |
771 | * to start output on the interface. This is done after | 775 | * to start output on the interface. This is done after | |
772 | * handling the receiver to give the receiver priority. | 776 | * handling the receiver to give the receiver priority. | |
773 | */ | 777 | */ | |
774 | if_schedule_deferred_start(ifp); | 778 | if_schedule_deferred_start(ifp); | |
775 | 779 | |||
776 | /* | 780 | /* | |
777 | * Return NIC CR to standard state: page 0, remote DMA | 781 | * Return NIC CR to standard state: page 0, remote DMA | |
778 | * complete, start (toggling the TXP bit off, even if was just | 782 | * complete, start (toggling the TXP bit off, even if was just | |
779 | * set in the transmit routine, is *okay* - it is 'edge' | 783 | * set in the transmit routine, is *okay* - it is 'edge' | |
780 | * triggered from low to high). | 784 | * triggered from low to high). | |
781 | */ | 785 | */ | |
782 | NIC_BARRIER(regt, regh); | 786 | NIC_BARRIER(regt, regh); | |
783 | NIC_PUT(regt, regh, ED_P0_CR, | 787 | NIC_PUT(regt, regh, ED_P0_CR, | |
784 | sc->cr_proto | ED_CR_PAGE_0 | ED_CR_STA); | 788 | sc->cr_proto | ED_CR_PAGE_0 | ED_CR_STA); | |
785 | NIC_BARRIER(regt, regh); | 789 | NIC_BARRIER(regt, regh); | |
786 | 790 | |||
787 | /* | 791 | /* | |
788 | * If the Network Talley Counters overflow, read them to reset | 792 | * If the Network Talley Counters overflow, read them to reset | |
789 | * them. It appears that old 8390's won't clear the ISR flag | 793 | * them. It appears that old 8390's won't clear the ISR flag | |
790 | * otherwise - resulting in an infinite loop. | 794 | * otherwise - resulting in an infinite loop. | |
791 | */ | 795 | */ | |
792 | if ((isr & ED_ISR_CNT) != 0) { | 796 | if ((isr & ED_ISR_CNT) != 0) { | |
793 | (void)NIC_GET(regt, regh, ED_P0_CNTR0); | 797 | (void)NIC_GET(regt, regh, ED_P0_CNTR0); | |
794 | (void)NIC_GET(regt, regh, ED_P0_CNTR1); | 798 | (void)NIC_GET(regt, regh, ED_P0_CNTR1); | |
795 | (void)NIC_GET(regt, regh, ED_P0_CNTR2); | 799 | (void)NIC_GET(regt, regh, ED_P0_CNTR2); | |
796 | } | 800 | } | |
797 | 801 | |||
798 | isr = NIC_GET(regt, regh, ED_P0_ISR); | 802 | isr = NIC_GET(regt, regh, ED_P0_ISR); | |
799 | if (isr == 0) | 803 | if (isr == 0) | |
800 | goto out; | 804 | goto out; | |
801 | } | 805 | } | |
802 | 806 | |||
803 | out: | 807 | out: | |
804 | rnd_add_uint32(&sc->rnd_source, rndisr); | 808 | rnd_add_uint32(&sc->rnd_source, rndisr); | |
805 | return 1; | 809 | return 1; | |
806 | } | 810 | } | |
807 | 811 | |||
808 | /* | 812 | /* | |
809 | * Process an ioctl request. This code needs some work - it looks pretty ugly. | 813 | * Process an ioctl request. This code needs some work - it looks pretty ugly. | |
810 | */ | 814 | */ | |
811 | int | 815 | int | |
812 | dp8390_ioctl(struct ifnet *ifp, u_long cmd, void *data) | 816 | dp8390_ioctl(struct ifnet *ifp, u_long cmd, void *data) | |
813 | { | 817 | { | |
814 | struct dp8390_softc *sc = ifp->if_softc; | 818 | struct dp8390_softc *sc = ifp->if_softc; | |
815 | struct ifaddr *ifa = data; | 819 | struct ifaddr *ifa = data; | |
816 | int s, error = 0; | 820 | int s, error = 0; | |
817 | 821 | |||
818 | s = splnet(); | 822 | s = splnet(); | |
819 | 823 | |||
820 | switch (cmd) { | 824 | switch (cmd) { | |
821 | 825 | |||
822 | case SIOCINITIFADDR: | 826 | case SIOCINITIFADDR: | |
823 | if ((error = dp8390_enable(sc)) != 0) | 827 | if ((error = dp8390_enable(sc)) != 0) | |
824 | break; | 828 | break; | |
825 | ifp->if_flags |= IFF_UP; | 829 | ifp->if_flags |= IFF_UP; | |
826 | 830 | |||
827 | dp8390_init(sc); | 831 | dp8390_init(sc); | |
828 | switch (ifa->ifa_addr->sa_family) { | 832 | switch (ifa->ifa_addr->sa_family) { | |
829 | #ifdef INET | 833 | #ifdef INET | |
830 | case AF_INET: | 834 | case AF_INET: | |
831 | arp_ifinit(ifp, ifa); | 835 | arp_ifinit(ifp, ifa); | |
832 | break; | 836 | break; | |
833 | #endif | 837 | #endif | |
834 | default: | 838 | default: | |
835 | break; | 839 | break; | |
836 | } | 840 | } | |
837 | break; | 841 | break; | |
838 | 842 | |||
839 | case SIOCSIFFLAGS: | 843 | case SIOCSIFFLAGS: | |
840 | if ((error = ifioctl_common(ifp, cmd, data)) != 0) | 844 | if ((error = ifioctl_common(ifp, cmd, data)) != 0) | |
841 | break; | 845 | break; | |
842 | switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) { | 846 | switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) { | |
843 | case IFF_RUNNING: | 847 | case IFF_RUNNING: | |
844 | /* | 848 | /* | |
845 | * If interface is marked down and it is running, then | 849 | * If interface is marked down and it is running, then | |
846 | * stop it. | 850 | * stop it. | |
847 | */ | 851 | */ | |
848 | dp8390_stop(sc); | 852 | dp8390_stop(sc); | |
849 | ifp->if_flags &= ~IFF_RUNNING; | 853 | ifp->if_flags &= ~IFF_RUNNING; | |
850 | dp8390_disable(sc); | 854 | dp8390_disable(sc); | |
851 | break; | 855 | break; | |
852 | case IFF_UP: | 856 | case IFF_UP: | |
853 | /* | 857 | /* | |
854 | * If interface is marked up and it is stopped, then | 858 | * If interface is marked up and it is stopped, then | |
855 | * start it. | 859 | * start it. | |
856 | */ | 860 | */ | |
857 | if ((error = dp8390_enable(sc)) != 0) | 861 | if ((error = dp8390_enable(sc)) != 0) | |
858 | break; | 862 | break; | |
859 | dp8390_init(sc); | 863 | dp8390_init(sc); | |
860 | break; | 864 | break; | |
861 | case IFF_UP | IFF_RUNNING: | 865 | case IFF_UP | IFF_RUNNING: | |
862 | /* | 866 | /* | |
863 | * Reset the interface to pick up changes in any other | 867 | * Reset the interface to pick up changes in any other | |
864 | * flags that affect hardware registers. | 868 | * flags that affect hardware registers. | |
865 | */ | 869 | */ | |
866 | dp8390_stop(sc); | 870 | dp8390_stop(sc); | |
867 | dp8390_init(sc); | 871 | dp8390_init(sc); | |
868 | break; | 872 | break; | |
869 | default: | 873 | default: | |
870 | break; | 874 | break; | |
871 | } | 875 | } | |
872 | break; | 876 | break; | |
873 | 877 | |||
874 | case SIOCADDMULTI: | 878 | case SIOCADDMULTI: | |
875 | case SIOCDELMULTI: | 879 | case SIOCDELMULTI: | |
876 | if (sc->sc_enabled == 0) { | 880 | if (sc->sc_enabled == 0) { | |
877 | error = EIO; | 881 | error = EIO; | |
878 | break; | 882 | break; | |
879 | } | 883 | } | |
880 | 884 | |||
881 | /* Update our multicast list. */ | 885 | /* Update our multicast list. */ | |
882 | if ((error = ether_ioctl(ifp, cmd, data)) == ENETRESET) { | 886 | if ((error = ether_ioctl(ifp, cmd, data)) == ENETRESET) { | |
883 | /* | 887 | /* | |
884 | * Multicast list has changed; set the hardware filter | 888 | * Multicast list has changed; set the hardware filter | |
885 | * accordingly. | 889 | * accordingly. | |
886 | */ | 890 | */ | |
887 | if (ifp->if_flags & IFF_RUNNING) { | 891 | if (ifp->if_flags & IFF_RUNNING) { | |
888 | dp8390_stop(sc); /* XXX for ds_setmcaf? */ | 892 | dp8390_stop(sc); /* XXX for ds_setmcaf? */ | |
889 | dp8390_init(sc); | 893 | dp8390_init(sc); | |
890 | } | 894 | } | |
891 | error = 0; | 895 | error = 0; | |
892 | } | 896 | } | |
893 | break; | 897 | break; | |
894 | 898 | |||
895 | default: | 899 | default: | |
896 | error = ether_ioctl(ifp, cmd, data); | 900 | error = ether_ioctl(ifp, cmd, data); | |
897 | break; | 901 | break; | |
898 | } | 902 | } | |
899 | 903 | |||
900 | splx(s); | 904 | splx(s); | |
901 | return error; | 905 | return error; | |
902 | } | 906 | } | |
903 | 907 | |||
904 | /* | 908 | /* | |
905 | * Retrieve packet from buffer memory and send to the next level up via | 909 | * Retrieve packet from buffer memory and send to the next level up via | |
906 | * ether_input(). If there is a BPF listener, give a copy to BPF, too. | 910 | * ether_input(). If there is a BPF listener, give a copy to BPF, too. | |
907 | */ | 911 | */ | |
908 | void | 912 | void | |
909 | dp8390_read(struct dp8390_softc *sc, int buf, u_short len) | 913 | dp8390_read(struct dp8390_softc *sc, int buf, u_short len) | |
910 | { | 914 | { | |
911 | struct ifnet *ifp = &sc->sc_ec.ec_if; | 915 | struct ifnet *ifp = &sc->sc_ec.ec_if; | |
912 | struct mbuf *m; | 916 | struct mbuf *m; | |
913 | 917 | |||
914 | /* Pull packet off interface. */ | 918 | /* Pull packet off interface. */ | |
915 | m = dp8390_get(sc, buf, len); | 919 | m = dp8390_get(sc, buf, len); | |
916 | if (m == NULL) { | 920 | if (m == NULL) { | |
917 | ifp->if_ierrors++; | 921 | if_statinc(ifp, if_ierrors); | |
918 | return; | 922 | return; | |
919 | } | 923 | } | |
920 | 924 | |||
921 | if_percpuq_enqueue(ifp->if_percpuq, m); | 925 | if_percpuq_enqueue(ifp->if_percpuq, m); | |
922 | } | 926 | } | |
923 | 927 | |||
924 | 928 | |||
925 | /* | 929 | /* | |
926 | * Supporting routines. | 930 | * Supporting routines. | |
927 | */ | 931 | */ | |
928 | 932 | |||
929 | /* | 933 | /* | |
930 | * Compute the multicast address filter from the list of multicast addresses we | 934 | * Compute the multicast address filter from the list of multicast addresses we | |
931 | * need to listen to. | 935 | * need to listen to. | |
932 | */ | 936 | */ | |
933 | void | 937 | void | |
934 | dp8390_getmcaf(struct ethercom *ec, uint8_t *af) | 938 | dp8390_getmcaf(struct ethercom *ec, uint8_t *af) | |
935 | { | 939 | { | |
936 | struct ifnet *ifp = &ec->ec_if; | 940 | struct ifnet *ifp = &ec->ec_if; | |
937 | struct ether_multi *enm; | 941 | struct ether_multi *enm; | |
938 | uint32_t crc; | 942 | uint32_t crc; | |
939 | int i; | 943 | int i; | |
940 | struct ether_multistep step; | 944 | struct ether_multistep step; | |
941 | 945 | |||
942 | /* | 946 | /* | |
943 | * Set up multicast address filter by passing all multicast addresses | 947 | * Set up multicast address filter by passing all multicast addresses | |
944 | * through a crc generator, and then using the high order 6 bits as an | 948 | * through a crc generator, and then using the high order 6 bits as an | |
945 | * index into the 64 bit logical address filter. The high order bit | 949 | * index into the 64 bit logical address filter. The high order bit | |
946 | * selects the word, while the rest of the bits select the bit within | 950 | * selects the word, while the rest of the bits select the bit within | |
947 | * the word. | 951 | * the word. | |
948 | */ | 952 | */ | |
949 | 953 | |||
950 | if (ifp->if_flags & IFF_PROMISC) { | 954 | if (ifp->if_flags & IFF_PROMISC) { | |
951 | ifp->if_flags |= IFF_ALLMULTI; | 955 | ifp->if_flags |= IFF_ALLMULTI; | |
952 | for (i = 0; i < 8; i++) | 956 | for (i = 0; i < 8; i++) | |
953 | af[i] = 0xff; | 957 | af[i] = 0xff; | |
954 | return; | 958 | return; | |
955 | } | 959 | } | |
956 | for (i = 0; i < 8; i++) | 960 | for (i = 0; i < 8; i++) | |
957 | af[i] = 0; | 961 | af[i] = 0; | |
958 | ETHER_LOCK(ec); | 962 | ETHER_LOCK(ec); | |
959 | ETHER_FIRST_MULTI(step, ec, enm); | 963 | ETHER_FIRST_MULTI(step, ec, enm); | |
960 | while (enm != NULL) { | 964 | while (enm != NULL) { | |
961 | if (memcmp(enm->enm_addrlo, enm->enm_addrhi, | 965 | if (memcmp(enm->enm_addrlo, enm->enm_addrhi, | |
962 | sizeof(enm->enm_addrlo)) != 0) { | 966 | sizeof(enm->enm_addrlo)) != 0) { | |
963 | /* | 967 | /* | |
964 | * We must listen to a range of multicast addresses. | 968 | * We must listen to a range of multicast addresses. | |
965 | * For now, just accept all multicasts, rather than | 969 | * For now, just accept all multicasts, rather than | |
966 | * trying to set only those filter bits needed to match | 970 | * trying to set only those filter bits needed to match | |
967 | * the range. (At this time, the only use of address | 971 | * the range. (At this time, the only use of address | |
968 | * ranges is for IP multicast routing, for which the | 972 | * ranges is for IP multicast routing, for which the | |
969 | * range is big enough to require all bits set.) | 973 | * range is big enough to require all bits set.) | |
970 | */ | 974 | */ | |
971 | ifp->if_flags |= IFF_ALLMULTI; | 975 | ifp->if_flags |= IFF_ALLMULTI; | |
972 | for (i = 0; i < 8; i++) | 976 | for (i = 0; i < 8; i++) | |
973 | af[i] = 0xff; | 977 | af[i] = 0xff; | |
974 | ETHER_UNLOCK(ec); | 978 | ETHER_UNLOCK(ec); | |
975 | return; | 979 | return; | |
976 | } | 980 | } | |
977 | 981 | |||
978 | crc = ether_crc32_be(enm->enm_addrlo, ETHER_ADDR_LEN); | 982 | crc = ether_crc32_be(enm->enm_addrlo, ETHER_ADDR_LEN); | |
979 | 983 | |||
980 | /* Just want the 6 most significant bits. */ | 984 | /* Just want the 6 most significant bits. */ | |
981 | crc >>= 26; | 985 | crc >>= 26; | |
982 | 986 | |||
983 | /* Turn on the corresponding bit in the filter. */ | 987 | /* Turn on the corresponding bit in the filter. */ | |
984 | af[crc >> 3] |= 1 << (crc & 0x7); | 988 | af[crc >> 3] |= 1 << (crc & 0x7); | |
985 | 989 | |||
986 | ETHER_NEXT_MULTI(step, enm); | 990 | ETHER_NEXT_MULTI(step, enm); | |
987 | } | 991 | } | |
988 | ETHER_UNLOCK(ec); | 992 | ETHER_UNLOCK(ec); | |
989 | ifp->if_flags &= ~IFF_ALLMULTI; | 993 | ifp->if_flags &= ~IFF_ALLMULTI; | |
990 | } | 994 | } | |
991 | 995 | |||
992 | /* | 996 | /* | |
993 | * Copy data from receive buffer to a new mbuf chain allocating mbufs | 997 | * Copy data from receive buffer to a new mbuf chain allocating mbufs | |
994 | * as needed. Return pointer to first mbuf in chain. | 998 | * as needed. Return pointer to first mbuf in chain. | |
995 | * sc = dp8390 info (softc) | 999 | * sc = dp8390 info (softc) | |
996 | * src = pointer in dp8390 ring buffer | 1000 | * src = pointer in dp8390 ring buffer | |
997 | * total_len = amount of data to copy | 1001 | * total_len = amount of data to copy | |
998 | */ | 1002 | */ | |
999 | struct mbuf * | 1003 | struct mbuf * | |
1000 | dp8390_get(struct dp8390_softc *sc, int src, u_short total_len) | 1004 | dp8390_get(struct dp8390_softc *sc, int src, u_short total_len) | |
1001 | { | 1005 | { | |
1002 | struct ifnet *ifp = &sc->sc_ec.ec_if; | 1006 | struct ifnet *ifp = &sc->sc_ec.ec_if; | |
1003 | struct mbuf *m, *m0, *newm; | 1007 | struct mbuf *m, *m0, *newm; | |
1004 | u_short len; | 1008 | u_short len; | |
1005 | 1009 | |||
1006 | MGETHDR(m0, M_DONTWAIT, MT_DATA); | 1010 | MGETHDR(m0, M_DONTWAIT, MT_DATA); | |
1007 | if (m0 == NULL) | 1011 | if (m0 == NULL) | |
1008 | return NULL; | 1012 | return NULL; | |
1009 | m_set_rcvif(m0, ifp); | 1013 | m_set_rcvif(m0, ifp); | |
1010 | m0->m_pkthdr.len = total_len; | 1014 | m0->m_pkthdr.len = total_len; | |
1011 | len = MHLEN; | 1015 | len = MHLEN; | |
1012 | m = m0; | 1016 | m = m0; | |
1013 | 1017 | |||
1014 | while (total_len > 0) { | 1018 | while (total_len > 0) { | |
1015 | if (total_len >= MINCLSIZE) { | 1019 | if (total_len >= MINCLSIZE) { | |
1016 | MCLGET(m, M_DONTWAIT); | 1020 | MCLGET(m, M_DONTWAIT); | |
1017 | if ((m->m_flags & M_EXT) == 0) | 1021 | if ((m->m_flags & M_EXT) == 0) | |
1018 | goto bad; | 1022 | goto bad; | |
1019 | len = MCLBYTES; | 1023 | len = MCLBYTES; | |
1020 | } | 1024 | } | |
1021 | 1025 | |||
1022 | /* Make sure the data after the Ethernet header is aligned. */ | 1026 | /* Make sure the data after the Ethernet header is aligned. */ | |
1023 | if (m == m0) { | 1027 | if (m == m0) { | |
1024 | char *newdata = (char *) | 1028 | char *newdata = (char *) | |
1025 | ALIGN(m->m_data + sizeof(struct ether_header)) - | 1029 | ALIGN(m->m_data + sizeof(struct ether_header)) - | |
1026 | sizeof(struct ether_header); | 1030 | sizeof(struct ether_header); | |
1027 | len -= newdata - m->m_data; | 1031 | len -= newdata - m->m_data; | |
1028 | m->m_data = newdata; | 1032 | m->m_data = newdata; | |
1029 | } | 1033 | } | |
1030 | 1034 | |||
1031 | m->m_len = len = uimin(total_len, len); | 1035 | m->m_len = len = uimin(total_len, len); | |
1032 | src = (*sc->ring_copy)(sc, src, mtod(m, void *), len); | 1036 | src = (*sc->ring_copy)(sc, src, mtod(m, void *), len); | |
1033 | 1037 | |||
1034 | total_len -= len; | 1038 | total_len -= len; | |
1035 | if (total_len > 0) { | 1039 | if (total_len > 0) { | |
1036 | MGET(newm, M_DONTWAIT, MT_DATA); | 1040 | MGET(newm, M_DONTWAIT, MT_DATA); | |
1037 | if (newm == NULL) | 1041 | if (newm == NULL) | |
1038 | goto bad; | 1042 | goto bad; | |
1039 | len = MLEN; | 1043 | len = MLEN; | |
1040 | m = m->m_next = newm; | 1044 | m = m->m_next = newm; | |
1041 | } | 1045 | } | |
1042 | } | 1046 | } | |
1043 | 1047 | |||
1044 | return m0; | 1048 | return m0; | |
1045 | 1049 | |||
1046 | bad: | 1050 | bad: | |
1047 | m_freem(m0); | 1051 | m_freem(m0); | |
1048 | return NULL; | 1052 | return NULL; | |
1049 | } | 1053 | } | |
1050 | 1054 | |||
1051 | 1055 | |||
1052 | /* | 1056 | /* | |
1053 | * Default driver support functions. | 1057 | * Default driver support functions. | |
1054 | * | 1058 | * | |
1055 | * NOTE: all support functions assume 8-bit shared memory. | 1059 | * NOTE: all support functions assume 8-bit shared memory. | |
1056 | */ | 1060 | */ | |
1057 | /* | 1061 | /* | |
1058 | * Zero NIC buffer memory and verify that it is clear. | 1062 | * Zero NIC buffer memory and verify that it is clear. | |
1059 | */ | 1063 | */ | |
1060 | static int | 1064 | static int | |
1061 | dp8390_test_mem(struct dp8390_softc *sc) | 1065 | dp8390_test_mem(struct dp8390_softc *sc) | |
1062 | { | 1066 | { | |
1063 | bus_space_tag_t buft = sc->sc_buft; | 1067 | bus_space_tag_t buft = sc->sc_buft; | |
1064 | bus_space_handle_t bufh = sc->sc_bufh; | 1068 | bus_space_handle_t bufh = sc->sc_bufh; | |
1065 | int i; | 1069 | int i; | |
1066 | 1070 | |||
1067 | bus_space_set_region_1(buft, bufh, sc->mem_start, 0, sc->mem_size); | 1071 | bus_space_set_region_1(buft, bufh, sc->mem_start, 0, sc->mem_size); | |
1068 | 1072 | |||
1069 | for (i = 0; i < sc->mem_size; ++i) { | 1073 | for (i = 0; i < sc->mem_size; ++i) { | |
1070 | if (bus_space_read_1(buft, bufh, sc->mem_start + i)) { | 1074 | if (bus_space_read_1(buft, bufh, sc->mem_start + i)) { | |
1071 | printf(": failed to clear NIC buffer at offset %x - " | 1075 | printf(": failed to clear NIC buffer at offset %x - " | |
1072 | "check configuration\n", (sc->mem_start + i)); | 1076 | "check configuration\n", (sc->mem_start + i)); | |
1073 | return 1; | 1077 | return 1; | |
1074 | } | 1078 | } | |
1075 | } | 1079 | } | |
1076 | 1080 | |||
1077 | return 0; | 1081 | return 0; | |
1078 | } | 1082 | } | |
1079 | 1083 | |||
1080 | /* | 1084 | /* | |
1081 | * Read a packet header from the ring, given the source offset. | 1085 | * Read a packet header from the ring, given the source offset. | |
1082 | */ | 1086 | */ | |
1083 | static void | 1087 | static void | |
1084 | dp8390_read_hdr(struct dp8390_softc *sc, int src, struct dp8390_ring *hdrp) | 1088 | dp8390_read_hdr(struct dp8390_softc *sc, int src, struct dp8390_ring *hdrp) | |
1085 | { | 1089 | { | |
1086 | bus_space_tag_t buft = sc->sc_buft; | 1090 | bus_space_tag_t buft = sc->sc_buft; | |
1087 | bus_space_handle_t bufh = sc->sc_bufh; | 1091 | bus_space_handle_t bufh = sc->sc_bufh; | |
1088 | 1092 | |||
1089 | /* | 1093 | /* | |
1090 | * The byte count includes a 4 byte header that was added by | 1094 | * The byte count includes a 4 byte header that was added by | |
1091 | * the NIC. | 1095 | * the NIC. | |
1092 | */ | 1096 | */ | |
1093 | hdrp->rsr = bus_space_read_1(buft, bufh, src); | 1097 | hdrp->rsr = bus_space_read_1(buft, bufh, src); | |
1094 | hdrp->next_packet = bus_space_read_1(buft, bufh, src + 1); | 1098 | hdrp->next_packet = bus_space_read_1(buft, bufh, src + 1); | |
1095 | hdrp->count = bus_space_read_1(buft, bufh, src + 2) | | 1099 | hdrp->count = bus_space_read_1(buft, bufh, src + 2) | | |
1096 | (bus_space_read_1(buft, bufh, src + 3) << 8); | 1100 | (bus_space_read_1(buft, bufh, src + 3) << 8); | |
1097 | } | 1101 | } | |
1098 | 1102 | |||
1099 | /* | 1103 | /* | |
1100 | * Copy `amount' bytes from a packet in the ring buffer to a linear | 1104 | * Copy `amount' bytes from a packet in the ring buffer to a linear | |
1101 | * destination buffer, given a source offset and destination address. | 1105 | * destination buffer, given a source offset and destination address. | |
1102 | * Takes into account ring-wrap. | 1106 | * Takes into account ring-wrap. | |
1103 | */ | 1107 | */ | |
1104 | static int | 1108 | static int | |
1105 | dp8390_ring_copy(struct dp8390_softc *sc, int src, void *dst, u_short amount) | 1109 | dp8390_ring_copy(struct dp8390_softc *sc, int src, void *dst, u_short amount) | |
1106 | { | 1110 | { | |
1107 | bus_space_tag_t buft = sc->sc_buft; | 1111 | bus_space_tag_t buft = sc->sc_buft; | |
1108 | bus_space_handle_t bufh = sc->sc_bufh; | 1112 | bus_space_handle_t bufh = sc->sc_bufh; | |
1109 | u_short tmp_amount; | 1113 | u_short tmp_amount; | |
1110 | 1114 | |||
1111 | /* Does copy wrap to lower addr in ring buffer? */ | 1115 | /* Does copy wrap to lower addr in ring buffer? */ | |
1112 | if (src + amount > sc->mem_end) { | 1116 | if (src + amount > sc->mem_end) { | |
1113 | tmp_amount = sc->mem_end - src; | 1117 | tmp_amount = sc->mem_end - src; | |
1114 | 1118 | |||
1115 | /* Copy amount up to end of NIC memory. */ | 1119 | /* Copy amount up to end of NIC memory. */ | |
1116 | bus_space_read_region_1(buft, bufh, src, dst, tmp_amount); | 1120 | bus_space_read_region_1(buft, bufh, src, dst, tmp_amount); | |
1117 | 1121 | |||
1118 | amount -= tmp_amount; | 1122 | amount -= tmp_amount; | |
1119 | src = sc->mem_ring; | 1123 | src = sc->mem_ring; | |
1120 | dst = (char *)dst + tmp_amount; | 1124 | dst = (char *)dst + tmp_amount; | |
1121 | } | 1125 | } | |
1122 | bus_space_read_region_1(buft, bufh, src, dst, amount); | 1126 | bus_space_read_region_1(buft, bufh, src, dst, amount); | |
1123 | 1127 | |||
1124 | return src + amount; | 1128 | return src + amount; | |
1125 | } | 1129 | } | |
1126 | 1130 | |||
1127 | /* | 1131 | /* | |
1128 | * Copy a packet from an mbuf to the transmit buffer on the card. | 1132 | * Copy a packet from an mbuf to the transmit buffer on the card. | |
1129 | * | 1133 | * | |
1130 | * Currently uses an extra buffer/extra memory copy, unless the whole | 1134 | * Currently uses an extra buffer/extra memory copy, unless the whole | |
1131 | * packet fits in one mbuf. | 1135 | * packet fits in one mbuf. | |
1132 | */ | 1136 | */ | |
1133 | static int | 1137 | static int | |
1134 | dp8390_write_mbuf(struct dp8390_softc *sc, struct mbuf *m, int buf) | 1138 | dp8390_write_mbuf(struct dp8390_softc *sc, struct mbuf *m, int buf) | |
1135 | { | 1139 | { | |
1136 | bus_space_tag_t buft = sc->sc_buft; | 1140 | bus_space_tag_t buft = sc->sc_buft; | |
1137 | bus_space_handle_t bufh = sc->sc_bufh; | 1141 | bus_space_handle_t bufh = sc->sc_bufh; | |
1138 | uint8_t *data; | 1142 | uint8_t *data; | |
1139 | int len, totlen = 0; | 1143 | int len, totlen = 0; | |
1140 | 1144 | |||
1141 | for (; m ; m = m->m_next) { | 1145 | for (; m ; m = m->m_next) { | |
1142 | data = mtod(m, uint8_t *); | 1146 | data = mtod(m, uint8_t *); | |
1143 | len = m->m_len; | 1147 | len = m->m_len; | |
1144 | if (len > 0) { | 1148 | if (len > 0) { | |
1145 | bus_space_write_region_1(buft, bufh, buf, data, len); | 1149 | bus_space_write_region_1(buft, bufh, buf, data, len); | |
1146 | totlen += len; | 1150 | totlen += len; | |
1147 | buf += len; | 1151 | buf += len; | |
1148 | } | 1152 | } | |
1149 | } | 1153 | } | |
1150 | if (totlen < ETHER_MIN_LEN - ETHER_CRC_LEN) { | 1154 | if (totlen < ETHER_MIN_LEN - ETHER_CRC_LEN) { | |
1151 | bus_space_set_region_1(buft, bufh, buf, 0, | 1155 | bus_space_set_region_1(buft, bufh, buf, 0, | |
1152 | ETHER_MIN_LEN - ETHER_CRC_LEN - totlen); | 1156 | ETHER_MIN_LEN - ETHER_CRC_LEN - totlen); | |
1153 | totlen = ETHER_MIN_LEN - ETHER_CRC_LEN; | 1157 | totlen = ETHER_MIN_LEN - ETHER_CRC_LEN; | |
1154 | } | 1158 | } | |
1155 | return totlen; | 1159 | return totlen; | |
1156 | } | 1160 | } | |
1157 | 1161 | |||
1158 | /* | 1162 | /* | |
1159 | * Enable power on the interface. | 1163 | * Enable power on the interface. | |
1160 | */ | 1164 | */ | |
1161 | int | 1165 | int | |
1162 | dp8390_enable(struct dp8390_softc *sc) | 1166 | dp8390_enable(struct dp8390_softc *sc) | |
1163 | { | 1167 | { | |
1164 | 1168 | |||
1165 | if (sc->sc_enabled == 0 && sc->sc_enable != NULL) { | 1169 | if (sc->sc_enabled == 0 && sc->sc_enable != NULL) { | |
1166 | if ((*sc->sc_enable)(sc) != 0) { | 1170 | if ((*sc->sc_enable)(sc) != 0) { | |
1167 | aprint_error_dev(sc->sc_dev, | 1171 | aprint_error_dev(sc->sc_dev, | |
1168 | "device enable failed\n"); | 1172 | "device enable failed\n"); | |
1169 | return EIO; | 1173 | return EIO; | |
1170 | } | 1174 | } | |
1171 | } | 1175 | } | |
1172 | 1176 | |||
1173 | sc->sc_enabled = 1; | 1177 | sc->sc_enabled = 1; | |
1174 | return 0; | 1178 | return 0; | |
1175 | } | 1179 | } | |
1176 | 1180 | |||
1177 | /* | 1181 | /* | |
1178 | * Disable power on the interface. | 1182 | * Disable power on the interface. | |
1179 | */ | 1183 | */ | |
1180 | void | 1184 | void | |
1181 | dp8390_disable(struct dp8390_softc *sc) | 1185 | dp8390_disable(struct dp8390_softc *sc) | |
1182 | { | 1186 | { | |
1183 | 1187 | |||
1184 | if (sc->sc_enabled != 0 && sc->sc_disable != NULL) { | 1188 | if (sc->sc_enabled != 0 && sc->sc_disable != NULL) { | |
1185 | (*sc->sc_disable)(sc); | 1189 | (*sc->sc_disable)(sc); | |
1186 | sc->sc_enabled = 0; | 1190 | sc->sc_enabled = 0; | |
1187 | } | 1191 | } | |
1188 | } | 1192 | } | |
1189 | 1193 | |||
1190 | int | 1194 | int | |
1191 | dp8390_activate(device_t self, enum devact act) | 1195 | dp8390_activate(device_t self, enum devact act) | |
1192 | { | 1196 | { | |
1193 | struct dp8390_softc *sc = device_private(self); | 1197 | struct dp8390_softc *sc = device_private(self); | |
1194 | 1198 | |||
1195 | switch (act) { | 1199 | switch (act) { | |
1196 | case DVACT_DEACTIVATE: | 1200 | case DVACT_DEACTIVATE: | |
1197 | if_deactivate(&sc->sc_ec.ec_if); | 1201 | if_deactivate(&sc->sc_ec.ec_if); | |
1198 | return 0; | 1202 | return 0; | |
1199 | default: | 1203 | default: | |
1200 | return EOPNOTSUPP; | 1204 | return EOPNOTSUPP; | |
1201 | } | 1205 | } | |
1202 | } | 1206 | } | |
1203 | 1207 | |||
1204 | int | 1208 | int | |
1205 | dp8390_detach(struct dp8390_softc *sc, int flags) | 1209 | dp8390_detach(struct dp8390_softc *sc, int flags) | |
1206 | { | 1210 | { | |
1207 | struct ifnet *ifp = &sc->sc_ec.ec_if; | 1211 | struct ifnet *ifp = &sc->sc_ec.ec_if; | |
1208 | 1212 | |||
1209 | /* Succeed now if there's no work to do. */ | 1213 | /* Succeed now if there's no work to do. */ | |
1210 | if ((sc->sc_flags & DP8390_ATTACHED) == 0) | 1214 | if ((sc->sc_flags & DP8390_ATTACHED) == 0) | |
1211 | return 0; | 1215 | return 0; | |
1212 | 1216 | |||
1213 | /* dp8390_disable() checks sc->sc_enabled */ | 1217 | /* dp8390_disable() checks sc->sc_enabled */ | |
1214 | dp8390_disable(sc); | 1218 | dp8390_disable(sc); | |
1215 | 1219 | |||
1216 | if (sc->sc_media_fini != NULL) | 1220 | if (sc->sc_media_fini != NULL) | |
1217 | (*sc->sc_media_fini)(sc); | 1221 | (*sc->sc_media_fini)(sc); | |
1218 | 1222 | |||
1219 | /* Delete all remaining media. */ | 1223 | /* Delete all remaining media. */ | |
1220 | ifmedia_delete_instance(&sc->sc_media, IFM_INST_ANY); | 1224 | ifmedia_delete_instance(&sc->sc_media, IFM_INST_ANY); | |
1221 | 1225 | |||
1222 | rnd_detach_source(&sc->rnd_source); | 1226 | rnd_detach_source(&sc->rnd_source); | |
1223 | ether_ifdetach(ifp); | 1227 | ether_ifdetach(ifp); | |
1224 | if_detach(ifp); | 1228 | if_detach(ifp); | |
1225 | 1229 | |||
1226 | return 0; | 1230 | return 0; | |
1227 | } | 1231 | } |
--- src/sys/dev/ic/dp83932.c 2019/05/28 07:41:48 1.44
+++ src/sys/dev/ic/dp83932.c 2020/01/29 14:14:55 1.45
@@ -1,1262 +1,1266 @@ | @@ -1,1262 +1,1266 @@ | |||
1 | /* $NetBSD: dp83932.c,v 1.44 2019/05/28 07:41:48 msaitoh Exp $ */ | 1 | /* $NetBSD: dp83932.c,v 1.45 2020/01/29 14:14:55 thorpej Exp $ */ | |
2 | 2 | |||
3 | /*- | 3 | /*- | |
4 | * Copyright (c) 2001 The NetBSD Foundation, Inc. | 4 | * Copyright (c) 2001 The NetBSD Foundation, Inc. | |
5 | * All rights reserved. | 5 | * All rights reserved. | |
6 | * | 6 | * | |
7 | * This code is derived from software contributed to The NetBSD Foundation | 7 | * This code is derived from software contributed to The NetBSD Foundation | |
8 | * by Jason R. Thorpe. | 8 | * by Jason R. Thorpe. | |
9 | * | 9 | * | |
10 | * Redistribution and use in source and binary forms, with or without | 10 | * Redistribution and use in source and binary forms, with or without | |
11 | * modification, are permitted provided that the following conditions | 11 | * modification, are permitted provided that the following conditions | |
12 | * are met: | 12 | * are met: | |
13 | * 1. Redistributions of source code must retain the above copyright | 13 | * 1. Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | 14 | * notice, this list of conditions and the following disclaimer. | |
15 | * 2. Redistributions in binary form must reproduce the above copyright | 15 | * 2. Redistributions in binary form must reproduce the above copyright | |
16 | * notice, this list of conditions and the following disclaimer in the | 16 | * notice, this list of conditions and the following disclaimer in the | |
17 | * documentation and/or other materials provided with the distribution. | 17 | * documentation and/or other materials provided with the distribution. | |
18 | * | 18 | * | |
19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | 19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | |
20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | 20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | |
21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | 21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | 22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | |
23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | 23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | 24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | 27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
29 | * POSSIBILITY OF SUCH DAMAGE. | 29 | * POSSIBILITY OF SUCH DAMAGE. | |
30 | */ | 30 | */ | |
31 | 31 | |||
32 | /* | 32 | /* | |
33 | * Device driver for the National Semiconductor DP83932 | 33 | * Device driver for the National Semiconductor DP83932 | |
34 | * Systems-Oriented Network Interface Controller (SONIC). | 34 | * Systems-Oriented Network Interface Controller (SONIC). | |
35 | */ | 35 | */ | |
36 | 36 | |||
37 | #include <sys/cdefs.h> | 37 | #include <sys/cdefs.h> | |
38 | __KERNEL_RCSID(0, "$NetBSD: dp83932.c,v 1.44 2019/05/28 07:41:48 msaitoh Exp $"); | 38 | __KERNEL_RCSID(0, "$NetBSD: dp83932.c,v 1.45 2020/01/29 14:14:55 thorpej Exp $"); | |
39 | 39 | |||
40 | 40 | |||
41 | #include <sys/param.h> | 41 | #include <sys/param.h> | |
42 | #include <sys/systm.h> | 42 | #include <sys/systm.h> | |
43 | #include <sys/mbuf.h> | 43 | #include <sys/mbuf.h> | |
44 | #include <sys/malloc.h> | 44 | #include <sys/malloc.h> | |
45 | #include <sys/kernel.h> | 45 | #include <sys/kernel.h> | |
46 | #include <sys/socket.h> | 46 | #include <sys/socket.h> | |
47 | #include <sys/ioctl.h> | 47 | #include <sys/ioctl.h> | |
48 | #include <sys/errno.h> | 48 | #include <sys/errno.h> | |
49 | #include <sys/device.h> | 49 | #include <sys/device.h> | |
50 | 50 | |||
51 | #include <net/if.h> | 51 | #include <net/if.h> | |
52 | #include <net/if_dl.h> | 52 | #include <net/if_dl.h> | |
53 | #include <net/if_ether.h> | 53 | #include <net/if_ether.h> | |
54 | 54 | |||
55 | #include <net/bpf.h> | 55 | #include <net/bpf.h> | |
56 | 56 | |||
57 | #include <sys/bus.h> | 57 | #include <sys/bus.h> | |
58 | #include <sys/intr.h> | 58 | #include <sys/intr.h> | |
59 | 59 | |||
60 | #include <dev/ic/dp83932reg.h> | 60 | #include <dev/ic/dp83932reg.h> | |
61 | #include <dev/ic/dp83932var.h> | 61 | #include <dev/ic/dp83932var.h> | |
62 | 62 | |||
63 | static void sonic_start(struct ifnet *); | 63 | static void sonic_start(struct ifnet *); | |
64 | static void sonic_watchdog(struct ifnet *); | 64 | static void sonic_watchdog(struct ifnet *); | |
65 | static int sonic_ioctl(struct ifnet *, u_long, void *); | 65 | static int sonic_ioctl(struct ifnet *, u_long, void *); | |
66 | static int sonic_init(struct ifnet *); | 66 | static int sonic_init(struct ifnet *); | |
67 | static void sonic_stop(struct ifnet *, int); | 67 | static void sonic_stop(struct ifnet *, int); | |
68 | 68 | |||
69 | static bool sonic_shutdown(device_t, int); | 69 | static bool sonic_shutdown(device_t, int); | |
70 | 70 | |||
71 | static void sonic_reset(struct sonic_softc *); | 71 | static void sonic_reset(struct sonic_softc *); | |
72 | static void sonic_rxdrain(struct sonic_softc *); | 72 | static void sonic_rxdrain(struct sonic_softc *); | |
73 | static int sonic_add_rxbuf(struct sonic_softc *, int); | 73 | static int sonic_add_rxbuf(struct sonic_softc *, int); | |
74 | static void sonic_set_filter(struct sonic_softc *); | 74 | static void sonic_set_filter(struct sonic_softc *); | |
75 | 75 | |||
76 | static uint16_t sonic_txintr(struct sonic_softc *); | 76 | static uint16_t sonic_txintr(struct sonic_softc *); | |
77 | static void sonic_rxintr(struct sonic_softc *); | 77 | static void sonic_rxintr(struct sonic_softc *); | |
78 | 78 | |||
79 | int sonic_copy_small = 0; | 79 | int sonic_copy_small = 0; | |
80 | 80 | |||
81 | #define ETHER_PAD_LEN (ETHER_MIN_LEN - ETHER_CRC_LEN) | 81 | #define ETHER_PAD_LEN (ETHER_MIN_LEN - ETHER_CRC_LEN) | |
82 | 82 | |||
83 | /* | 83 | /* | |
84 | * sonic_attach: | 84 | * sonic_attach: | |
85 | * | 85 | * | |
86 | * Attach a SONIC interface to the system. | 86 | * Attach a SONIC interface to the system. | |
87 | */ | 87 | */ | |
88 | void | 88 | void | |
89 | sonic_attach(struct sonic_softc *sc, const uint8_t *enaddr) | 89 | sonic_attach(struct sonic_softc *sc, const uint8_t *enaddr) | |
90 | { | 90 | { | |
91 | struct ifnet *ifp = &sc->sc_ethercom.ec_if; | 91 | struct ifnet *ifp = &sc->sc_ethercom.ec_if; | |
92 | int i, rseg, error; | 92 | int i, rseg, error; | |
93 | bus_dma_segment_t seg; | 93 | bus_dma_segment_t seg; | |
94 | size_t cdatasize; | 94 | size_t cdatasize; | |
95 | uint8_t *nullbuf; | 95 | uint8_t *nullbuf; | |
96 | 96 | |||
97 | /* | 97 | /* | |
98 | * Allocate the control data structures, and create and load the | 98 | * Allocate the control data structures, and create and load the | |
99 | * DMA map for it. | 99 | * DMA map for it. | |
100 | */ | 100 | */ | |
101 | if (sc->sc_32bit) | 101 | if (sc->sc_32bit) | |
102 | cdatasize = sizeof(struct sonic_control_data32); | 102 | cdatasize = sizeof(struct sonic_control_data32); | |
103 | else | 103 | else | |
104 | cdatasize = sizeof(struct sonic_control_data16); | 104 | cdatasize = sizeof(struct sonic_control_data16); | |
105 | 105 | |||
106 | if ((error = bus_dmamem_alloc(sc->sc_dmat, cdatasize + ETHER_PAD_LEN, | 106 | if ((error = bus_dmamem_alloc(sc->sc_dmat, cdatasize + ETHER_PAD_LEN, | |
107 | PAGE_SIZE, (64 * 1024), &seg, 1, &rseg, | 107 | PAGE_SIZE, (64 * 1024), &seg, 1, &rseg, | |
108 | BUS_DMA_NOWAIT)) != 0) { | 108 | BUS_DMA_NOWAIT)) != 0) { | |
109 | aprint_error_dev(sc->sc_dev, | 109 | aprint_error_dev(sc->sc_dev, | |
110 | "unable to allocate control data, error = %d\n", error); | 110 | "unable to allocate control data, error = %d\n", error); | |
111 | goto fail_0; | 111 | goto fail_0; | |
112 | } | 112 | } | |
113 | 113 | |||
114 | if ((error = bus_dmamem_map(sc->sc_dmat, &seg, rseg, | 114 | if ((error = bus_dmamem_map(sc->sc_dmat, &seg, rseg, | |
115 | cdatasize + ETHER_PAD_LEN, (void **) &sc->sc_cdata16, | 115 | cdatasize + ETHER_PAD_LEN, (void **) &sc->sc_cdata16, | |
116 | BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) != 0) { | 116 | BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) != 0) { | |
117 | aprint_error_dev(sc->sc_dev, | 117 | aprint_error_dev(sc->sc_dev, | |
118 | "unable to map control data, error = %d\n", error); | 118 | "unable to map control data, error = %d\n", error); | |
119 | goto fail_1; | 119 | goto fail_1; | |
120 | } | 120 | } | |
121 | nullbuf = (uint8_t *)sc->sc_cdata16 + cdatasize; | 121 | nullbuf = (uint8_t *)sc->sc_cdata16 + cdatasize; | |
122 | memset(nullbuf, 0, ETHER_PAD_LEN); | 122 | memset(nullbuf, 0, ETHER_PAD_LEN); | |
123 | 123 | |||
124 | if ((error = bus_dmamap_create(sc->sc_dmat, | 124 | if ((error = bus_dmamap_create(sc->sc_dmat, | |
125 | cdatasize, 1, cdatasize, 0, BUS_DMA_NOWAIT, | 125 | cdatasize, 1, cdatasize, 0, BUS_DMA_NOWAIT, | |
126 | &sc->sc_cddmamap)) != 0) { | 126 | &sc->sc_cddmamap)) != 0) { | |
127 | aprint_error_dev(sc->sc_dev, | 127 | aprint_error_dev(sc->sc_dev, | |
128 | "unable to create control data DMA map, error = %d\n", | 128 | "unable to create control data DMA map, error = %d\n", | |
129 | error); | 129 | error); | |
130 | goto fail_2; | 130 | goto fail_2; | |
131 | } | 131 | } | |
132 | 132 | |||
133 | if ((error = bus_dmamap_load(sc->sc_dmat, sc->sc_cddmamap, | 133 | if ((error = bus_dmamap_load(sc->sc_dmat, sc->sc_cddmamap, | |
134 | sc->sc_cdata16, cdatasize, NULL, BUS_DMA_NOWAIT)) != 0) { | 134 | sc->sc_cdata16, cdatasize, NULL, BUS_DMA_NOWAIT)) != 0) { | |
135 | aprint_error_dev(sc->sc_dev, | 135 | aprint_error_dev(sc->sc_dev, | |
136 | "unable to load control data DMA map, error = %d\n", error); | 136 | "unable to load control data DMA map, error = %d\n", error); | |
137 | goto fail_3; | 137 | goto fail_3; | |
138 | } | 138 | } | |
139 | 139 | |||
140 | /* | 140 | /* | |
141 | * Create the transmit buffer DMA maps. | 141 | * Create the transmit buffer DMA maps. | |
142 | */ | 142 | */ | |
143 | for (i = 0; i < SONIC_NTXDESC; i++) { | 143 | for (i = 0; i < SONIC_NTXDESC; i++) { | |
144 | if ((error = bus_dmamap_create(sc->sc_dmat, MCLBYTES, | 144 | if ((error = bus_dmamap_create(sc->sc_dmat, MCLBYTES, | |
145 | SONIC_NTXFRAGS, MCLBYTES, 0, BUS_DMA_NOWAIT, | 145 | SONIC_NTXFRAGS, MCLBYTES, 0, BUS_DMA_NOWAIT, | |
146 | &sc->sc_txsoft[i].ds_dmamap)) != 0) { | 146 | &sc->sc_txsoft[i].ds_dmamap)) != 0) { | |
147 | aprint_error_dev(sc->sc_dev, | 147 | aprint_error_dev(sc->sc_dev, | |
148 | "unable to create tx DMA map %d, error = %d\n", | 148 | "unable to create tx DMA map %d, error = %d\n", | |
149 | i, error); | 149 | i, error); | |
150 | goto fail_4; | 150 | goto fail_4; | |
151 | } | 151 | } | |
152 | } | 152 | } | |
153 | 153 | |||
154 | /* | 154 | /* | |
155 | * Create the receive buffer DMA maps. | 155 | * Create the receive buffer DMA maps. | |
156 | */ | 156 | */ | |
157 | for (i = 0; i < SONIC_NRXDESC; i++) { | 157 | for (i = 0; i < SONIC_NRXDESC; i++) { | |
158 | if ((error = bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1, | 158 | if ((error = bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1, | |
159 | MCLBYTES, 0, BUS_DMA_NOWAIT, | 159 | MCLBYTES, 0, BUS_DMA_NOWAIT, | |
160 | &sc->sc_rxsoft[i].ds_dmamap)) != 0) { | 160 | &sc->sc_rxsoft[i].ds_dmamap)) != 0) { | |
161 | aprint_error_dev(sc->sc_dev, | 161 | aprint_error_dev(sc->sc_dev, | |
162 | "unable to create rx DMA map %d, error = %d\n", | 162 | "unable to create rx DMA map %d, error = %d\n", | |
163 | i, error); | 163 | i, error); | |
164 | goto fail_5; | 164 | goto fail_5; | |
165 | } | 165 | } | |
166 | sc->sc_rxsoft[i].ds_mbuf = NULL; | 166 | sc->sc_rxsoft[i].ds_mbuf = NULL; | |
167 | } | 167 | } | |
168 | 168 | |||
169 | /* | 169 | /* | |
170 | * create and map the pad buffer | 170 | * create and map the pad buffer | |
171 | */ | 171 | */ | |
172 | if ((error = bus_dmamap_create(sc->sc_dmat, ETHER_PAD_LEN, 1, | 172 | if ((error = bus_dmamap_create(sc->sc_dmat, ETHER_PAD_LEN, 1, | |
173 | ETHER_PAD_LEN, 0, BUS_DMA_NOWAIT, &sc->sc_nulldmamap)) != 0) { | 173 | ETHER_PAD_LEN, 0, BUS_DMA_NOWAIT, &sc->sc_nulldmamap)) != 0) { | |
174 | aprint_error_dev(sc->sc_dev, | 174 | aprint_error_dev(sc->sc_dev, | |
175 | "unable to create pad buffer DMA map, error = %d\n", error); | 175 | "unable to create pad buffer DMA map, error = %d\n", error); | |
176 | goto fail_5; | 176 | goto fail_5; | |
177 | } | 177 | } | |
178 | 178 | |||
179 | if ((error = bus_dmamap_load(sc->sc_dmat, sc->sc_nulldmamap, | 179 | if ((error = bus_dmamap_load(sc->sc_dmat, sc->sc_nulldmamap, | |
180 | nullbuf, ETHER_PAD_LEN, NULL, BUS_DMA_NOWAIT)) != 0) { | 180 | nullbuf, ETHER_PAD_LEN, NULL, BUS_DMA_NOWAIT)) != 0) { | |
181 | aprint_error_dev(sc->sc_dev, | 181 | aprint_error_dev(sc->sc_dev, | |
182 | "unable to load pad buffer DMA map, error = %d\n", error); | 182 | "unable to load pad buffer DMA map, error = %d\n", error); | |
183 | goto fail_6; | 183 | goto fail_6; | |
184 | } | 184 | } | |
185 | bus_dmamap_sync(sc->sc_dmat, sc->sc_nulldmamap, 0, ETHER_PAD_LEN, | 185 | bus_dmamap_sync(sc->sc_dmat, sc->sc_nulldmamap, 0, ETHER_PAD_LEN, | |
186 | BUS_DMASYNC_PREWRITE); | 186 | BUS_DMASYNC_PREWRITE); | |
187 | 187 | |||
188 | /* | 188 | /* | |
189 | * Reset the chip to a known state. | 189 | * Reset the chip to a known state. | |
190 | */ | 190 | */ | |
191 | sonic_reset(sc); | 191 | sonic_reset(sc); | |
192 | 192 | |||
193 | aprint_normal_dev(sc->sc_dev, "Ethernet address %s\n", | 193 | aprint_normal_dev(sc->sc_dev, "Ethernet address %s\n", | |
194 | ether_sprintf(enaddr)); | 194 | ether_sprintf(enaddr)); | |
195 | 195 | |||
196 | strlcpy(ifp->if_xname, device_xname(sc->sc_dev), IFNAMSIZ); | 196 | strlcpy(ifp->if_xname, device_xname(sc->sc_dev), IFNAMSIZ); | |
197 | ifp->if_softc = sc; | 197 | ifp->if_softc = sc; | |
198 | ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; | 198 | ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; | |
199 | ifp->if_ioctl = sonic_ioctl; | 199 | ifp->if_ioctl = sonic_ioctl; | |
200 | ifp->if_start = sonic_start; | 200 | ifp->if_start = sonic_start; | |
201 | ifp->if_watchdog = sonic_watchdog; | 201 | ifp->if_watchdog = sonic_watchdog; | |
202 | ifp->if_init = sonic_init; | 202 | ifp->if_init = sonic_init; | |
203 | ifp->if_stop = sonic_stop; | 203 | ifp->if_stop = sonic_stop; | |
204 | IFQ_SET_READY(&ifp->if_snd); | 204 | IFQ_SET_READY(&ifp->if_snd); | |
205 | 205 | |||
206 | /* | 206 | /* | |
207 | * We can support 802.1Q VLAN-sized frames. | 207 | * We can support 802.1Q VLAN-sized frames. | |
208 | */ | 208 | */ | |
209 | sc->sc_ethercom.ec_capabilities |= ETHERCAP_VLAN_MTU; | 209 | sc->sc_ethercom.ec_capabilities |= ETHERCAP_VLAN_MTU; | |
210 | 210 | |||
211 | /* | 211 | /* | |
212 | * Attach the interface. | 212 | * Attach the interface. | |
213 | */ | 213 | */ | |
214 | if_attach(ifp); | 214 | if_attach(ifp); | |
215 | if_deferred_start_init(ifp, NULL); | 215 | if_deferred_start_init(ifp, NULL); | |
216 | ether_ifattach(ifp, enaddr); | 216 | ether_ifattach(ifp, enaddr); | |
217 | 217 | |||
218 | /* | 218 | /* | |
219 | * Make sure the interface is shutdown during reboot. | 219 | * Make sure the interface is shutdown during reboot. | |
220 | */ | 220 | */ | |
221 | if (pmf_device_register1(sc->sc_dev, NULL, NULL, sonic_shutdown)) | 221 | if (pmf_device_register1(sc->sc_dev, NULL, NULL, sonic_shutdown)) | |
222 | pmf_class_network_register(sc->sc_dev, ifp); | 222 | pmf_class_network_register(sc->sc_dev, ifp); | |
223 | else | 223 | else | |
224 | aprint_error_dev(sc->sc_dev, | 224 | aprint_error_dev(sc->sc_dev, | |
225 | "couldn't establish power handler\n"); | 225 | "couldn't establish power handler\n"); | |
226 | 226 | |||
227 | return; | 227 | return; | |
228 | 228 | |||
229 | /* | 229 | /* | |
230 | * Free any resources we've allocated during the failed attach | 230 | * Free any resources we've allocated during the failed attach | |
231 | * attempt. Do this in reverse order and fall through. | 231 | * attempt. Do this in reverse order and fall through. | |
232 | */ | 232 | */ | |
233 | fail_6: | 233 | fail_6: | |
234 | bus_dmamap_destroy(sc->sc_dmat, sc->sc_nulldmamap); | 234 | bus_dmamap_destroy(sc->sc_dmat, sc->sc_nulldmamap); | |
235 | fail_5: | 235 | fail_5: | |
236 | for (i = 0; i < SONIC_NRXDESC; i++) { | 236 | for (i = 0; i < SONIC_NRXDESC; i++) { | |
237 | if (sc->sc_rxsoft[i].ds_dmamap != NULL) | 237 | if (sc->sc_rxsoft[i].ds_dmamap != NULL) | |
238 | bus_dmamap_destroy(sc->sc_dmat, | 238 | bus_dmamap_destroy(sc->sc_dmat, | |
239 | sc->sc_rxsoft[i].ds_dmamap); | 239 | sc->sc_rxsoft[i].ds_dmamap); | |
240 | } | 240 | } | |
241 | fail_4: | 241 | fail_4: | |
242 | for (i = 0; i < SONIC_NTXDESC; i++) { | 242 | for (i = 0; i < SONIC_NTXDESC; i++) { | |
243 | if (sc->sc_txsoft[i].ds_dmamap != NULL) | 243 | if (sc->sc_txsoft[i].ds_dmamap != NULL) | |
244 | bus_dmamap_destroy(sc->sc_dmat, | 244 | bus_dmamap_destroy(sc->sc_dmat, | |
245 | sc->sc_txsoft[i].ds_dmamap); | 245 | sc->sc_txsoft[i].ds_dmamap); | |
246 | } | 246 | } | |
247 | bus_dmamap_unload(sc->sc_dmat, sc->sc_cddmamap); | 247 | bus_dmamap_unload(sc->sc_dmat, sc->sc_cddmamap); | |
248 | fail_3: | 248 | fail_3: | |
249 | bus_dmamap_destroy(sc->sc_dmat, sc->sc_cddmamap); | 249 | bus_dmamap_destroy(sc->sc_dmat, sc->sc_cddmamap); | |
250 | fail_2: | 250 | fail_2: | |
251 | bus_dmamem_unmap(sc->sc_dmat, (void *)sc->sc_cdata16, cdatasize); | 251 | bus_dmamem_unmap(sc->sc_dmat, (void *)sc->sc_cdata16, cdatasize); | |
252 | fail_1: | 252 | fail_1: | |
253 | bus_dmamem_free(sc->sc_dmat, &seg, rseg); | 253 | bus_dmamem_free(sc->sc_dmat, &seg, rseg); | |
254 | fail_0: | 254 | fail_0: | |
255 | return; | 255 | return; | |
256 | } | 256 | } | |
257 | 257 | |||
258 | /* | 258 | /* | |
259 | * sonic_shutdown: | 259 | * sonic_shutdown: | |
260 | * | 260 | * | |
261 | * Make sure the interface is stopped at reboot. | 261 | * Make sure the interface is stopped at reboot. | |
262 | */ | 262 | */ | |
263 | bool | 263 | bool | |
264 | sonic_shutdown(device_t self, int howto) | 264 | sonic_shutdown(device_t self, int howto) | |
265 | { | 265 | { | |
266 | struct sonic_softc *sc = device_private(self); | 266 | struct sonic_softc *sc = device_private(self); | |
267 | 267 | |||
268 | sonic_stop(&sc->sc_ethercom.ec_if, 1); | 268 | sonic_stop(&sc->sc_ethercom.ec_if, 1); | |
269 | 269 | |||
270 | return true; | 270 | return true; | |
271 | } | 271 | } | |
272 | 272 | |||
273 | /* | 273 | /* | |
274 | * sonic_start: [ifnet interface function] | 274 | * sonic_start: [ifnet interface function] | |
275 | * | 275 | * | |
276 | * Start packet transmission on the interface. | 276 | * Start packet transmission on the interface. | |
277 | */ | 277 | */ | |
278 | void | 278 | void | |
279 | sonic_start(struct ifnet *ifp) | 279 | sonic_start(struct ifnet *ifp) | |
280 | { | 280 | { | |
281 | struct sonic_softc *sc = ifp->if_softc; | 281 | struct sonic_softc *sc = ifp->if_softc; | |
282 | struct mbuf *m0, *m; | 282 | struct mbuf *m0, *m; | |
283 | struct sonic_tda16 *tda16; | 283 | struct sonic_tda16 *tda16; | |
284 | struct sonic_tda32 *tda32; | 284 | struct sonic_tda32 *tda32; | |
285 | struct sonic_descsoft *ds; | 285 | struct sonic_descsoft *ds; | |
286 | bus_dmamap_t dmamap; | 286 | bus_dmamap_t dmamap; | |
287 | int error, olasttx, nexttx, opending, totlen, olseg; | 287 | int error, olasttx, nexttx, opending, totlen, olseg; | |
288 | int seg = 0; /* XXX: gcc */ | 288 | int seg = 0; /* XXX: gcc */ | |
289 | 289 | |||
290 | if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING) | 290 | if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING) | |
291 | return; | 291 | return; | |
292 | 292 | |||
293 | /* | 293 | /* | |
294 | * Remember the previous txpending and the current "last txdesc | 294 | * Remember the previous txpending and the current "last txdesc | |
295 | * used" index. | 295 | * used" index. | |
296 | */ | 296 | */ | |
297 | opending = sc->sc_txpending; | 297 | opending = sc->sc_txpending; | |
298 | olasttx = sc->sc_txlast; | 298 | olasttx = sc->sc_txlast; | |
299 | 299 | |||
300 | /* | 300 | /* | |
301 | * Loop through the send queue, setting up transmit descriptors | 301 | * Loop through the send queue, setting up transmit descriptors | |
302 | * until we drain the queue, or use up all available transmit | 302 | * until we drain the queue, or use up all available transmit | |
303 | * descriptors. Leave one at the end for sanity's sake. | 303 | * descriptors. Leave one at the end for sanity's sake. | |
304 | */ | 304 | */ | |
305 | while (sc->sc_txpending < (SONIC_NTXDESC - 1)) { | 305 | while (sc->sc_txpending < (SONIC_NTXDESC - 1)) { | |
306 | /* | 306 | /* | |
307 | * Grab a packet off the queue. | 307 | * Grab a packet off the queue. | |
308 | */ | 308 | */ | |
309 | IFQ_POLL(&ifp->if_snd, m0); | 309 | IFQ_POLL(&ifp->if_snd, m0); | |
310 | if (m0 == NULL) | 310 | if (m0 == NULL) | |
311 | break; | 311 | break; | |
312 | m = NULL; | 312 | m = NULL; | |
313 | 313 | |||
314 | /* | 314 | /* | |
315 | * Get the next available transmit descriptor. | 315 | * Get the next available transmit descriptor. | |
316 | */ | 316 | */ | |
317 | nexttx = SONIC_NEXTTX(sc->sc_txlast); | 317 | nexttx = SONIC_NEXTTX(sc->sc_txlast); | |
318 | ds = &sc->sc_txsoft[nexttx]; | 318 | ds = &sc->sc_txsoft[nexttx]; | |
319 | dmamap = ds->ds_dmamap; | 319 | dmamap = ds->ds_dmamap; | |
320 | 320 | |||
321 | /* | 321 | /* | |
322 | * Load the DMA map. If this fails, the packet either | 322 | * Load the DMA map. If this fails, the packet either | |
323 | * didn't fit in the allotted number of frags, or we were | 323 | * didn't fit in the allotted number of frags, or we were | |
324 | * short on resources. In this case, we'll copy and try | 324 | * short on resources. In this case, we'll copy and try | |
325 | * again. | 325 | * again. | |
326 | */ | 326 | */ | |
327 | if ((error = bus_dmamap_load_mbuf(sc->sc_dmat, dmamap, m0, | 327 | if ((error = bus_dmamap_load_mbuf(sc->sc_dmat, dmamap, m0, | |
328 | BUS_DMA_WRITE | BUS_DMA_NOWAIT)) != 0 || | 328 | BUS_DMA_WRITE | BUS_DMA_NOWAIT)) != 0 || | |
329 | (m0->m_pkthdr.len < ETHER_PAD_LEN && | 329 | (m0->m_pkthdr.len < ETHER_PAD_LEN && | |
330 | dmamap->dm_nsegs == SONIC_NTXFRAGS)) { | 330 | dmamap->dm_nsegs == SONIC_NTXFRAGS)) { | |
331 | if (error == 0) | 331 | if (error == 0) | |
332 | bus_dmamap_unload(sc->sc_dmat, dmamap); | 332 | bus_dmamap_unload(sc->sc_dmat, dmamap); | |
333 | MGETHDR(m, M_DONTWAIT, MT_DATA); | 333 | MGETHDR(m, M_DONTWAIT, MT_DATA); | |
334 | if (m == NULL) { | 334 | if (m == NULL) { | |
335 | printf("%s: unable to allocate Tx mbuf\n", | 335 | printf("%s: unable to allocate Tx mbuf\n", | |
336 | device_xname(sc->sc_dev)); | 336 | device_xname(sc->sc_dev)); | |
337 | break; | 337 | break; | |
338 | } | 338 | } | |
339 | if (m0->m_pkthdr.len > MHLEN) { | 339 | if (m0->m_pkthdr.len > MHLEN) { | |
340 | MCLGET(m, M_DONTWAIT); | 340 | MCLGET(m, M_DONTWAIT); | |
341 | if ((m->m_flags & M_EXT) == 0) { | 341 | if ((m->m_flags & M_EXT) == 0) { | |
342 | printf("%s: unable to allocate Tx " | 342 | printf("%s: unable to allocate Tx " | |
343 | "cluster\n", | 343 | "cluster\n", | |
344 | device_xname(sc->sc_dev)); | 344 | device_xname(sc->sc_dev)); | |
345 | m_freem(m); | 345 | m_freem(m); | |
346 | break; | 346 | break; | |
347 | } | 347 | } | |
348 | } | 348 | } | |
349 | m_copydata(m0, 0, m0->m_pkthdr.len, mtod(m, void *)); | 349 | m_copydata(m0, 0, m0->m_pkthdr.len, mtod(m, void *)); | |
350 | m->m_pkthdr.len = m->m_len = m0->m_pkthdr.len; | 350 | m->m_pkthdr.len = m->m_len = m0->m_pkthdr.len; | |
351 | error = bus_dmamap_load_mbuf(sc->sc_dmat, dmamap, | 351 | error = bus_dmamap_load_mbuf(sc->sc_dmat, dmamap, | |
352 | m, BUS_DMA_WRITE | BUS_DMA_NOWAIT); | 352 | m, BUS_DMA_WRITE | BUS_DMA_NOWAIT); | |
353 | if (error) { | 353 | if (error) { | |
354 | printf("%s: unable to load Tx buffer, " | 354 | printf("%s: unable to load Tx buffer, " | |
355 | "error = %d\n", device_xname(sc->sc_dev), | 355 | "error = %d\n", device_xname(sc->sc_dev), | |
356 | error); | 356 | error); | |
357 | m_freem(m); | 357 | m_freem(m); | |
358 | break; | 358 | break; | |
359 | } | 359 | } | |
360 | } | 360 | } | |
361 | IFQ_DEQUEUE(&ifp->if_snd, m0); | 361 | IFQ_DEQUEUE(&ifp->if_snd, m0); | |
362 | if (m != NULL) { | 362 | if (m != NULL) { | |
363 | m_freem(m0); | 363 | m_freem(m0); | |
364 | m0 = m; | 364 | m0 = m; | |
365 | } | 365 | } | |
366 | 366 | |||
367 | /* | 367 | /* | |
368 | * WE ARE NOW COMMITTED TO TRANSMITTING THE PACKET. | 368 | * WE ARE NOW COMMITTED TO TRANSMITTING THE PACKET. | |
369 | */ | 369 | */ | |
370 | 370 | |||
371 | /* Sync the DMA map. */ | 371 | /* Sync the DMA map. */ | |
372 | bus_dmamap_sync(sc->sc_dmat, dmamap, 0, dmamap->dm_mapsize, | 372 | bus_dmamap_sync(sc->sc_dmat, dmamap, 0, dmamap->dm_mapsize, | |
373 | BUS_DMASYNC_PREWRITE); | 373 | BUS_DMASYNC_PREWRITE); | |
374 | 374 | |||
375 | /* | 375 | /* | |
376 | * Store a pointer to the packet so we can free it later. | 376 | * Store a pointer to the packet so we can free it later. | |
377 | */ | 377 | */ | |
378 | ds->ds_mbuf = m0; | 378 | ds->ds_mbuf = m0; | |
379 | 379 | |||
380 | /* | 380 | /* | |
381 | * Initialize the transmit descriptor. | 381 | * Initialize the transmit descriptor. | |
382 | */ | 382 | */ | |
383 | totlen = 0; | 383 | totlen = 0; | |
384 | if (sc->sc_32bit) { | 384 | if (sc->sc_32bit) { | |
385 | tda32 = &sc->sc_tda32[nexttx]; | 385 | tda32 = &sc->sc_tda32[nexttx]; | |
386 | for (seg = 0; seg < dmamap->dm_nsegs; seg++) { | 386 | for (seg = 0; seg < dmamap->dm_nsegs; seg++) { | |
387 | tda32->tda_frags[seg].frag_ptr1 = | 387 | tda32->tda_frags[seg].frag_ptr1 = | |
388 | htosonic32(sc, | 388 | htosonic32(sc, | |
389 | (dmamap->dm_segs[seg].ds_addr >> 16) & | 389 | (dmamap->dm_segs[seg].ds_addr >> 16) & | |
390 | 0xffff); | 390 | 0xffff); | |
391 | tda32->tda_frags[seg].frag_ptr0 = | 391 | tda32->tda_frags[seg].frag_ptr0 = | |
392 | htosonic32(sc, | 392 | htosonic32(sc, | |
393 | dmamap->dm_segs[seg].ds_addr & 0xffff); | 393 | dmamap->dm_segs[seg].ds_addr & 0xffff); | |
394 | tda32->tda_frags[seg].frag_size = | 394 | tda32->tda_frags[seg].frag_size = | |
395 | htosonic32(sc, dmamap->dm_segs[seg].ds_len); | 395 | htosonic32(sc, dmamap->dm_segs[seg].ds_len); | |
396 | totlen += dmamap->dm_segs[seg].ds_len; | 396 | totlen += dmamap->dm_segs[seg].ds_len; | |
397 | } | 397 | } | |
398 | if (totlen < ETHER_PAD_LEN) { | 398 | if (totlen < ETHER_PAD_LEN) { | |
399 | tda32->tda_frags[seg].frag_ptr1 = | 399 | tda32->tda_frags[seg].frag_ptr1 = | |
400 | htosonic32(sc, | 400 | htosonic32(sc, | |
401 | (sc->sc_nulldma >> 16) & 0xffff); | 401 | (sc->sc_nulldma >> 16) & 0xffff); | |
402 | tda32->tda_frags[seg].frag_ptr0 = | 402 | tda32->tda_frags[seg].frag_ptr0 = | |
403 | htosonic32(sc, sc->sc_nulldma & 0xffff); | 403 | htosonic32(sc, sc->sc_nulldma & 0xffff); | |
404 | tda32->tda_frags[seg].frag_size = | 404 | tda32->tda_frags[seg].frag_size = | |
405 | htosonic32(sc, ETHER_PAD_LEN - totlen); | 405 | htosonic32(sc, ETHER_PAD_LEN - totlen); | |
406 | totlen = ETHER_PAD_LEN; | 406 | totlen = ETHER_PAD_LEN; | |
407 | seg++; | 407 | seg++; | |
408 | } | 408 | } | |
409 | 409 | |||
410 | tda32->tda_status = 0; | 410 | tda32->tda_status = 0; | |
411 | tda32->tda_pktconfig = 0; | 411 | tda32->tda_pktconfig = 0; | |
412 | tda32->tda_pktsize = htosonic32(sc, totlen); | 412 | tda32->tda_pktsize = htosonic32(sc, totlen); | |
413 | tda32->tda_fragcnt = htosonic32(sc, seg); | 413 | tda32->tda_fragcnt = htosonic32(sc, seg); | |
414 | 414 | |||
415 | /* Link it up. */ | 415 | /* Link it up. */ | |
416 | tda32->tda_frags[seg].frag_ptr0 = | 416 | tda32->tda_frags[seg].frag_ptr0 = | |
417 | htosonic32(sc, SONIC_CDTXADDR32(sc, | 417 | htosonic32(sc, SONIC_CDTXADDR32(sc, | |
418 | SONIC_NEXTTX(nexttx)) & 0xffff); | 418 | SONIC_NEXTTX(nexttx)) & 0xffff); | |
419 | 419 | |||
420 | /* Sync the Tx descriptor. */ | 420 | /* Sync the Tx descriptor. */ | |
421 | SONIC_CDTXSYNC32(sc, nexttx, | 421 | SONIC_CDTXSYNC32(sc, nexttx, | |
422 | BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); | 422 | BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); | |
423 | } else { | 423 | } else { | |
424 | tda16 = &sc->sc_tda16[nexttx]; | 424 | tda16 = &sc->sc_tda16[nexttx]; | |
425 | for (seg = 0; seg < dmamap->dm_nsegs; seg++) { | 425 | for (seg = 0; seg < dmamap->dm_nsegs; seg++) { | |
426 | tda16->tda_frags[seg].frag_ptr1 = | 426 | tda16->tda_frags[seg].frag_ptr1 = | |
427 | htosonic16(sc, | 427 | htosonic16(sc, | |
428 | (dmamap->dm_segs[seg].ds_addr >> 16) & | 428 | (dmamap->dm_segs[seg].ds_addr >> 16) & | |
429 | 0xffff); | 429 | 0xffff); | |
430 | tda16->tda_frags[seg].frag_ptr0 = | 430 | tda16->tda_frags[seg].frag_ptr0 = | |
431 | htosonic16(sc, | 431 | htosonic16(sc, | |
432 | dmamap->dm_segs[seg].ds_addr & 0xffff); | 432 | dmamap->dm_segs[seg].ds_addr & 0xffff); | |
433 | tda16->tda_frags[seg].frag_size = | 433 | tda16->tda_frags[seg].frag_size = | |
434 | htosonic16(sc, dmamap->dm_segs[seg].ds_len); | 434 | htosonic16(sc, dmamap->dm_segs[seg].ds_len); | |
435 | totlen += dmamap->dm_segs[seg].ds_len; | 435 | totlen += dmamap->dm_segs[seg].ds_len; | |
436 | } | 436 | } | |
437 | if (totlen < ETHER_PAD_LEN) { | 437 | if (totlen < ETHER_PAD_LEN) { | |
438 | tda16->tda_frags[seg].frag_ptr1 = | 438 | tda16->tda_frags[seg].frag_ptr1 = | |
439 | htosonic16(sc, | 439 | htosonic16(sc, | |
440 | (sc->sc_nulldma >> 16) & 0xffff); | 440 | (sc->sc_nulldma >> 16) & 0xffff); | |
441 | tda16->tda_frags[seg].frag_ptr0 = | 441 | tda16->tda_frags[seg].frag_ptr0 = | |
442 | htosonic16(sc, sc->sc_nulldma & 0xffff); | 442 | htosonic16(sc, sc->sc_nulldma & 0xffff); | |
443 | tda16->tda_frags[seg].frag_size = | 443 | tda16->tda_frags[seg].frag_size = | |
444 | htosonic16(sc, ETHER_PAD_LEN - totlen); | 444 | htosonic16(sc, ETHER_PAD_LEN - totlen); | |
445 | totlen = ETHER_PAD_LEN; | 445 | totlen = ETHER_PAD_LEN; | |
446 | seg++; | 446 | seg++; | |
447 | } | 447 | } | |
448 | 448 | |||
449 | tda16->tda_status = 0; | 449 | tda16->tda_status = 0; | |
450 | tda16->tda_pktconfig = 0; | 450 | tda16->tda_pktconfig = 0; | |
451 | tda16->tda_pktsize = htosonic16(sc, totlen); | 451 | tda16->tda_pktsize = htosonic16(sc, totlen); | |
452 | tda16->tda_fragcnt = htosonic16(sc, seg); | 452 | tda16->tda_fragcnt = htosonic16(sc, seg); | |
453 | 453 | |||
454 | /* Link it up. */ | 454 | /* Link it up. */ | |
455 | tda16->tda_frags[seg].frag_ptr0 = | 455 | tda16->tda_frags[seg].frag_ptr0 = | |
456 | htosonic16(sc, SONIC_CDTXADDR16(sc, | 456 | htosonic16(sc, SONIC_CDTXADDR16(sc, | |
457 | SONIC_NEXTTX(nexttx)) & 0xffff); | 457 | SONIC_NEXTTX(nexttx)) & 0xffff); | |
458 | 458 | |||
459 | /* Sync the Tx descriptor. */ | 459 | /* Sync the Tx descriptor. */ | |
460 | SONIC_CDTXSYNC16(sc, nexttx, | 460 | SONIC_CDTXSYNC16(sc, nexttx, | |
461 | BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); | 461 | BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); | |
462 | } | 462 | } | |
463 | 463 | |||
464 | /* Advance the Tx pointer. */ | 464 | /* Advance the Tx pointer. */ | |
465 | sc->sc_txpending++; | 465 | sc->sc_txpending++; | |
466 | sc->sc_txlast = nexttx; | 466 | sc->sc_txlast = nexttx; | |
467 | 467 | |||
468 | /* | 468 | /* | |
469 | * Pass the packet to any BPF listeners. | 469 | * Pass the packet to any BPF listeners. | |
470 | */ | 470 | */ | |
471 | bpf_mtap(ifp, m0, BPF_D_OUT); | 471 | bpf_mtap(ifp, m0, BPF_D_OUT); | |
472 | } | 472 | } | |
473 | 473 | |||
474 | if (sc->sc_txpending == (SONIC_NTXDESC - 1)) { | 474 | if (sc->sc_txpending == (SONIC_NTXDESC - 1)) { | |
475 | /* No more slots left; notify upper layer. */ | 475 | /* No more slots left; notify upper layer. */ | |
476 | ifp->if_flags |= IFF_OACTIVE; | 476 | ifp->if_flags |= IFF_OACTIVE; | |
477 | } | 477 | } | |
478 | 478 | |||
479 | if (sc->sc_txpending != opending) { | 479 | if (sc->sc_txpending != opending) { | |
480 | /* | 480 | /* | |
481 | * We enqueued packets. If the transmitter was idle, | 481 | * We enqueued packets. If the transmitter was idle, | |
482 | * reset the txdirty pointer. | 482 | * reset the txdirty pointer. | |
483 | */ | 483 | */ | |
484 | if (opending == 0) | 484 | if (opending == 0) | |
485 | sc->sc_txdirty = SONIC_NEXTTX(olasttx); | 485 | sc->sc_txdirty = SONIC_NEXTTX(olasttx); | |
486 | 486 | |||
487 | /* | 487 | /* | |
488 | * Stop the SONIC on the last packet we've set up, | 488 | * Stop the SONIC on the last packet we've set up, | |
489 | * and clear end-of-list on the descriptor previous | 489 | * and clear end-of-list on the descriptor previous | |
490 | * to our new chain. | 490 | * to our new chain. | |
491 | * | 491 | * | |
492 | * NOTE: our `seg' variable should still be valid! | 492 | * NOTE: our `seg' variable should still be valid! | |
493 | */ | 493 | */ | |
494 | if (sc->sc_32bit) { | 494 | if (sc->sc_32bit) { | |
495 | olseg = | 495 | olseg = | |
496 | sonic32toh(sc, sc->sc_tda32[olasttx].tda_fragcnt); | 496 | sonic32toh(sc, sc->sc_tda32[olasttx].tda_fragcnt); | |
497 | sc->sc_tda32[sc->sc_txlast].tda_frags[seg].frag_ptr0 |= | 497 | sc->sc_tda32[sc->sc_txlast].tda_frags[seg].frag_ptr0 |= | |
498 | htosonic32(sc, TDA_LINK_EOL); | 498 | htosonic32(sc, TDA_LINK_EOL); | |
499 | SONIC_CDTXSYNC32(sc, sc->sc_txlast, | 499 | SONIC_CDTXSYNC32(sc, sc->sc_txlast, | |
500 | BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); | 500 | BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); | |
501 | sc->sc_tda32[olasttx].tda_frags[olseg].frag_ptr0 &= | 501 | sc->sc_tda32[olasttx].tda_frags[olseg].frag_ptr0 &= | |
502 | htosonic32(sc, ~TDA_LINK_EOL); | 502 | htosonic32(sc, ~TDA_LINK_EOL); | |
503 | SONIC_CDTXSYNC32(sc, olasttx, | 503 | SONIC_CDTXSYNC32(sc, olasttx, | |
504 | BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); | 504 | BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); | |
505 | } else { | 505 | } else { | |
506 | olseg = | 506 | olseg = | |
507 | sonic16toh(sc, sc->sc_tda16[olasttx].tda_fragcnt); | 507 | sonic16toh(sc, sc->sc_tda16[olasttx].tda_fragcnt); | |
508 | sc->sc_tda16[sc->sc_txlast].tda_frags[seg].frag_ptr0 |= | 508 | sc->sc_tda16[sc->sc_txlast].tda_frags[seg].frag_ptr0 |= | |
509 | htosonic16(sc, TDA_LINK_EOL); | 509 | htosonic16(sc, TDA_LINK_EOL); | |
510 | SONIC_CDTXSYNC16(sc, sc->sc_txlast, | 510 | SONIC_CDTXSYNC16(sc, sc->sc_txlast, | |
511 | BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); | 511 | BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); | |
512 | sc->sc_tda16[olasttx].tda_frags[olseg].frag_ptr0 &= | 512 | sc->sc_tda16[olasttx].tda_frags[olseg].frag_ptr0 &= | |
513 | htosonic16(sc, ~TDA_LINK_EOL); | 513 | htosonic16(sc, ~TDA_LINK_EOL); | |
514 | SONIC_CDTXSYNC16(sc, olasttx, | 514 | SONIC_CDTXSYNC16(sc, olasttx, | |
515 | BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); | 515 | BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); | |
516 | } | 516 | } | |
517 | 517 | |||
518 | /* Start the transmitter. */ | 518 | /* Start the transmitter. */ | |
519 | CSR_WRITE(sc, SONIC_CR, CR_TXP); | 519 | CSR_WRITE(sc, SONIC_CR, CR_TXP); | |
520 | 520 | |||
521 | /* Set a watchdog timer in case the chip flakes out. */ | 521 | /* Set a watchdog timer in case the chip flakes out. */ | |
522 | ifp->if_timer = 5; | 522 | ifp->if_timer = 5; | |
523 | } | 523 | } | |
524 | } | 524 | } | |
525 | 525 | |||
526 | /* | 526 | /* | |
527 | * sonic_watchdog: [ifnet interface function] | 527 | * sonic_watchdog: [ifnet interface function] | |
528 | * | 528 | * | |
529 | * Watchdog timer handler. | 529 | * Watchdog timer handler. | |
530 | */ | 530 | */ | |
531 | void | 531 | void | |
532 | sonic_watchdog(struct ifnet *ifp) | 532 | sonic_watchdog(struct ifnet *ifp) | |
533 | { | 533 | { | |
534 | struct sonic_softc *sc = ifp->if_softc; | 534 | struct sonic_softc *sc = ifp->if_softc; | |
535 | 535 | |||
536 | printf("%s: device timeout\n", device_xname(sc->sc_dev)); | 536 | printf("%s: device timeout\n", device_xname(sc->sc_dev)); | |
537 | ifp->if_oerrors++; | 537 | if_statinc(ifp, if_oerrors); | |
538 | 538 | |||
539 | (void)sonic_init(ifp); | 539 | (void)sonic_init(ifp); | |
540 | } | 540 | } | |
541 | 541 | |||
542 | /* | 542 | /* | |
543 | * sonic_ioctl: [ifnet interface function] | 543 | * sonic_ioctl: [ifnet interface function] | |
544 | * | 544 | * | |
545 | * Handle control requests from the operator. | 545 | * Handle control requests from the operator. | |
546 | */ | 546 | */ | |
547 | int | 547 | int | |
548 | sonic_ioctl(struct ifnet *ifp, u_long cmd, void *data) | 548 | sonic_ioctl(struct ifnet *ifp, u_long cmd, void *data) | |
549 | { | 549 | { | |
550 | int s, error; | 550 | int s, error; | |
551 | 551 | |||
552 | s = splnet(); | 552 | s = splnet(); | |
553 | 553 | |||
554 | error = ether_ioctl(ifp, cmd, data); | 554 | error = ether_ioctl(ifp, cmd, data); | |
555 | if (error == ENETRESET) { | 555 | if (error == ENETRESET) { | |
556 | /* | 556 | /* | |
557 | * Multicast list has changed; set the hardware | 557 | * Multicast list has changed; set the hardware | |
558 | * filter accordingly. | 558 | * filter accordingly. | |
559 | */ | 559 | */ | |
560 | if (ifp->if_flags & IFF_RUNNING) | 560 | if (ifp->if_flags & IFF_RUNNING) | |
561 | (void)sonic_init(ifp); | 561 | (void)sonic_init(ifp); | |
562 | error = 0; | 562 | error = 0; | |
563 | } | 563 | } | |
564 | 564 | |||
565 | splx(s); | 565 | splx(s); | |
566 | return error; | 566 | return error; | |
567 | } | 567 | } | |
568 | 568 | |||
569 | /* | 569 | /* | |
570 | * sonic_intr: | 570 | * sonic_intr: | |
571 | * | 571 | * | |
572 | * Interrupt service routine. | 572 | * Interrupt service routine. | |
573 | */ | 573 | */ | |
574 | int | 574 | int | |
575 | sonic_intr(void *arg) | 575 | sonic_intr(void *arg) | |
576 | { | 576 | { | |
577 | struct sonic_softc *sc = arg; | 577 | struct sonic_softc *sc = arg; | |
578 | struct ifnet *ifp = &sc->sc_ethercom.ec_if; | 578 | struct ifnet *ifp = &sc->sc_ethercom.ec_if; | |
579 | uint16_t isr; | 579 | uint16_t isr; | |
580 | int handled = 0, wantinit; | 580 | int handled = 0, wantinit; | |
581 | 581 | |||
582 | for (wantinit = 0; wantinit == 0;) { | 582 | for (wantinit = 0; wantinit == 0;) { | |
583 | isr = CSR_READ(sc, SONIC_ISR) & sc->sc_imr; | 583 | isr = CSR_READ(sc, SONIC_ISR) & sc->sc_imr; | |
584 | if (isr == 0) | 584 | if (isr == 0) | |
585 | break; | 585 | break; | |
586 | CSR_WRITE(sc, SONIC_ISR, isr); /* ACK */ | 586 | CSR_WRITE(sc, SONIC_ISR, isr); /* ACK */ | |
587 | 587 | |||
588 | handled = 1; | 588 | handled = 1; | |
589 | 589 | |||
590 | if (isr & IMR_PRX) | 590 | if (isr & IMR_PRX) | |
591 | sonic_rxintr(sc); | 591 | sonic_rxintr(sc); | |
592 | 592 | |||
593 | if (isr & (IMR_PTX | IMR_TXER)) { | 593 | if (isr & (IMR_PTX | IMR_TXER)) { | |
594 | if (sonic_txintr(sc) & TCR_FU) { | 594 | if (sonic_txintr(sc) & TCR_FU) { | |
595 | printf("%s: transmit FIFO underrun\n", | 595 | printf("%s: transmit FIFO underrun\n", | |
596 | device_xname(sc->sc_dev)); | 596 | device_xname(sc->sc_dev)); | |
597 | wantinit = 1; | 597 | wantinit = 1; | |
598 | } | 598 | } | |
599 | } | 599 | } | |
600 | 600 | |||
601 | if (isr & (IMR_RFO | IMR_RBA | IMR_RBE | IMR_RDE)) { | 601 | if (isr & (IMR_RFO | IMR_RBA | IMR_RBE | IMR_RDE)) { | |
602 | #define PRINTERR(bit, str) \ | 602 | #define PRINTERR(bit, str) \ | |
603 | if (isr & (bit)) \ | 603 | if (isr & (bit)) \ | |
604 | printf("%s: %s\n",device_xname(sc->sc_dev), str) | 604 | printf("%s: %s\n",device_xname(sc->sc_dev), str) | |
605 | PRINTERR(IMR_RFO, "receive FIFO overrun"); | 605 | PRINTERR(IMR_RFO, "receive FIFO overrun"); | |
606 | PRINTERR(IMR_RBA, "receive buffer exceeded"); | 606 | PRINTERR(IMR_RBA, "receive buffer exceeded"); | |
607 | PRINTERR(IMR_RBE, "receive buffers exhausted"); | 607 | PRINTERR(IMR_RBE, "receive buffers exhausted"); | |
608 | PRINTERR(IMR_RDE, "receive descriptors exhausted"); | 608 | PRINTERR(IMR_RDE, "receive descriptors exhausted"); | |
609 | wantinit = 1; | 609 | wantinit = 1; | |
610 | } | 610 | } | |
611 | } | 611 | } | |
612 | 612 | |||
613 | if (handled) { | 613 | if (handled) { | |
614 | if (wantinit) | 614 | if (wantinit) | |
615 | (void)sonic_init(ifp); | 615 | (void)sonic_init(ifp); | |
616 | if_schedule_deferred_start(ifp); | 616 | if_schedule_deferred_start(ifp); | |
617 | } | 617 | } | |
618 | 618 | |||
619 | return handled; | 619 | return handled; | |
620 | } | 620 | } | |
621 | 621 | |||
622 | /* | 622 | /* | |
623 | * sonic_txintr: | 623 | * sonic_txintr: | |
624 | * | 624 | * | |
625 | * Helper; handle transmit complete interrupts. | 625 | * Helper; handle transmit complete interrupts. | |
626 | */ | 626 | */ | |
627 | uint16_t | 627 | uint16_t | |
628 | sonic_txintr(struct sonic_softc *sc) | 628 | sonic_txintr(struct sonic_softc *sc) | |
629 | { | 629 | { | |
630 | struct ifnet *ifp = &sc->sc_ethercom.ec_if; | 630 | struct ifnet *ifp = &sc->sc_ethercom.ec_if; | |
631 | struct sonic_descsoft *ds; | 631 | struct sonic_descsoft *ds; | |
632 | struct sonic_tda32 *tda32; | 632 | struct sonic_tda32 *tda32; | |
633 | struct sonic_tda16 *tda16; | 633 | struct sonic_tda16 *tda16; | |
634 | uint16_t status, totstat = 0; | 634 | uint16_t status, totstat = 0; | |
635 | int i; | 635 | int i; | |
636 | 636 | |||
637 | ifp->if_flags &= ~IFF_OACTIVE; | 637 | ifp->if_flags &= ~IFF_OACTIVE; | |
638 | 638 | |||
639 | for (i = sc->sc_txdirty; sc->sc_txpending != 0; | 639 | for (i = sc->sc_txdirty; sc->sc_txpending != 0; | |
640 | i = SONIC_NEXTTX(i), sc->sc_txpending--) { | 640 | i = SONIC_NEXTTX(i), sc->sc_txpending--) { | |
641 | ds = &sc->sc_txsoft[i]; | 641 | ds = &sc->sc_txsoft[i]; | |
642 | 642 | |||
643 | if (sc->sc_32bit) { | 643 | if (sc->sc_32bit) { | |
644 | SONIC_CDTXSYNC32(sc, i, | 644 | SONIC_CDTXSYNC32(sc, i, | |
645 | BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); | 645 | BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); | |
646 | tda32 = &sc->sc_tda32[i]; | 646 | tda32 = &sc->sc_tda32[i]; | |
647 | status = sonic32toh(sc, tda32->tda_status); | 647 | status = sonic32toh(sc, tda32->tda_status); | |
648 | SONIC_CDTXSYNC32(sc, i, BUS_DMASYNC_PREREAD); | 648 | SONIC_CDTXSYNC32(sc, i, BUS_DMASYNC_PREREAD); | |
649 | } else { | 649 | } else { | |
650 | SONIC_CDTXSYNC16(sc, i, | 650 | SONIC_CDTXSYNC16(sc, i, | |
651 | BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); | 651 | BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); | |
652 | tda16 = &sc->sc_tda16[i]; | 652 | tda16 = &sc->sc_tda16[i]; | |
653 | status = sonic16toh(sc, tda16->tda_status); | 653 | status = sonic16toh(sc, tda16->tda_status); | |
654 | SONIC_CDTXSYNC16(sc, i, BUS_DMASYNC_PREREAD); | 654 | SONIC_CDTXSYNC16(sc, i, BUS_DMASYNC_PREREAD); | |
655 | } | 655 | } | |
656 | 656 | |||
657 | if ((status & ~(TCR_EXDIS |TCR_CRCI |TCR_POWC |TCR_PINT)) == 0) | 657 | if ((status & ~(TCR_EXDIS |TCR_CRCI |TCR_POWC |TCR_PINT)) == 0) | |
658 | break; | 658 | break; | |
659 | 659 | |||
660 | totstat |= status; | 660 | totstat |= status; | |
661 | 661 | |||
662 | bus_dmamap_sync(sc->sc_dmat, ds->ds_dmamap, 0, | 662 | bus_dmamap_sync(sc->sc_dmat, ds->ds_dmamap, 0, | |
663 | ds->ds_dmamap->dm_mapsize, BUS_DMASYNC_POSTWRITE); | 663 | ds->ds_dmamap->dm_mapsize, BUS_DMASYNC_POSTWRITE); | |
664 | bus_dmamap_unload(sc->sc_dmat, ds->ds_dmamap); | 664 | bus_dmamap_unload(sc->sc_dmat, ds->ds_dmamap); | |
665 | m_freem(ds->ds_mbuf); | 665 | m_freem(ds->ds_mbuf); | |
666 | ds->ds_mbuf = NULL; | 666 | ds->ds_mbuf = NULL; | |
667 | 667 | |||
668 | /* | 668 | /* | |
669 | * Check for errors and collisions. | 669 | * Check for errors and collisions. | |
670 | */ | 670 | */ | |
671 | net_stat_ref_t nsr = IF_STAT_GETREF(ifp); | |||
671 | if (status & TCR_PTX) | 672 | if (status & TCR_PTX) | |
672 | ifp->if_opackets++; | 673 | if_statinc_ref(nsr, if_opackets); | |
673 | else | 674 | else | |
674 | ifp->if_oerrors++; | 675 | if_statinc_ref(nsr, if_oerrors); | |
675 | ifp->if_collisions += TDA_STATUS_NCOL(status); | 676 | if (TDA_STATUS_NCOL(status)) | |
677 | if_statadd_ref(nsr, if_collisions, | |||
678 | TDA_STATUS_NCOL(status)); | |||
679 | IF_STAT_PUTREF(ifp); | |||
676 | } | 680 | } | |
677 | 681 | |||
678 | /* Update the dirty transmit buffer pointer. */ | 682 | /* Update the dirty transmit buffer pointer. */ | |
679 | sc->sc_txdirty = i; | 683 | sc->sc_txdirty = i; | |
680 | 684 | |||
681 | /* | 685 | /* | |
682 | * Cancel the watchdog timer if there are no pending | 686 | * Cancel the watchdog timer if there are no pending | |
683 | * transmissions. | 687 | * transmissions. | |
684 | */ | 688 | */ | |
685 | if (sc->sc_txpending == 0) | 689 | if (sc->sc_txpending == 0) | |
686 | ifp->if_timer = 0; | 690 | ifp->if_timer = 0; | |
687 | 691 | |||
688 | return totstat; | 692 | return totstat; | |
689 | } | 693 | } | |
690 | 694 | |||
691 | /* | 695 | /* | |
692 | * sonic_rxintr: | 696 | * sonic_rxintr: | |
693 | * | 697 | * | |
694 | * Helper; handle receive interrupts. | 698 | * Helper; handle receive interrupts. | |
695 | */ | 699 | */ | |
696 | void | 700 | void | |
697 | sonic_rxintr(struct sonic_softc *sc) | 701 | sonic_rxintr(struct sonic_softc *sc) | |
698 | { | 702 | { | |
699 | struct ifnet *ifp = &sc->sc_ethercom.ec_if; | 703 | struct ifnet *ifp = &sc->sc_ethercom.ec_if; | |
700 | struct sonic_descsoft *ds; | 704 | struct sonic_descsoft *ds; | |
701 | struct sonic_rda32 *rda32; | 705 | struct sonic_rda32 *rda32; | |
702 | struct sonic_rda16 *rda16; | 706 | struct sonic_rda16 *rda16; | |
703 | struct mbuf *m; | 707 | struct mbuf *m; | |
704 | int i, len; | 708 | int i, len; | |
705 | uint16_t status, bytecount /*, ptr0, ptr1, seqno */; | 709 | uint16_t status, bytecount /*, ptr0, ptr1, seqno */; | |
706 | 710 | |||
707 | for (i = sc->sc_rxptr;; i = SONIC_NEXTRX(i)) { | 711 | for (i = sc->sc_rxptr;; i = SONIC_NEXTRX(i)) { | |
708 | ds = &sc->sc_rxsoft[i]; | 712 | ds = &sc->sc_rxsoft[i]; | |
709 | 713 | |||
710 | if (sc->sc_32bit) { | 714 | if (sc->sc_32bit) { | |
711 | SONIC_CDRXSYNC32(sc, i, | 715 | SONIC_CDRXSYNC32(sc, i, | |
712 | BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); | 716 | BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); | |
713 | rda32 = &sc->sc_rda32[i]; | 717 | rda32 = &sc->sc_rda32[i]; | |
714 | SONIC_CDRXSYNC32(sc, i, BUS_DMASYNC_PREREAD); | 718 | SONIC_CDRXSYNC32(sc, i, BUS_DMASYNC_PREREAD); | |
715 | if (rda32->rda_inuse != 0) | 719 | if (rda32->rda_inuse != 0) | |
716 | break; | 720 | break; | |
717 | status = sonic32toh(sc, rda32->rda_status); | 721 | status = sonic32toh(sc, rda32->rda_status); | |
718 | bytecount = sonic32toh(sc, rda32->rda_bytecount); | 722 | bytecount = sonic32toh(sc, rda32->rda_bytecount); | |
719 | /* ptr0 = sonic32toh(sc, rda32->rda_pkt_ptr0); */ | 723 | /* ptr0 = sonic32toh(sc, rda32->rda_pkt_ptr0); */ | |
720 | /* ptr1 = sonic32toh(sc, rda32->rda_pkt_ptr1); */ | 724 | /* ptr1 = sonic32toh(sc, rda32->rda_pkt_ptr1); */ | |
721 | /* seqno = sonic32toh(sc, rda32->rda_seqno); */ | 725 | /* seqno = sonic32toh(sc, rda32->rda_seqno); */ | |
722 | } else { | 726 | } else { | |
723 | SONIC_CDRXSYNC16(sc, i, | 727 | SONIC_CDRXSYNC16(sc, i, | |
724 | BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); | 728 | BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); | |
725 | rda16 = &sc->sc_rda16[i]; | 729 | rda16 = &sc->sc_rda16[i]; | |
726 | SONIC_CDRXSYNC16(sc, i, BUS_DMASYNC_PREREAD); | 730 | SONIC_CDRXSYNC16(sc, i, BUS_DMASYNC_PREREAD); | |
727 | if (rda16->rda_inuse != 0) | 731 | if (rda16->rda_inuse != 0) | |
728 | break; | 732 | break; | |
729 | status = sonic16toh(sc, rda16->rda_status); | 733 | status = sonic16toh(sc, rda16->rda_status); | |
730 | bytecount = sonic16toh(sc, rda16->rda_bytecount); | 734 | bytecount = sonic16toh(sc, rda16->rda_bytecount); | |
731 | /* ptr0 = sonic16toh(sc, rda16->rda_pkt_ptr0); */ | 735 | /* ptr0 = sonic16toh(sc, rda16->rda_pkt_ptr0); */ | |
732 | /* ptr1 = sonic16toh(sc, rda16->rda_pkt_ptr1); */ | 736 | /* ptr1 = sonic16toh(sc, rda16->rda_pkt_ptr1); */ | |
733 | /* seqno = sonic16toh(sc, rda16->rda_seqno); */ | 737 | /* seqno = sonic16toh(sc, rda16->rda_seqno); */ | |
734 | } | 738 | } | |
735 | 739 | |||
736 | /* | 740 | /* | |
737 | * Make absolutely sure this is the only packet | 741 | * Make absolutely sure this is the only packet | |
738 | * in this receive buffer. Our entire Rx buffer | 742 | * in this receive buffer. Our entire Rx buffer | |
739 | * management scheme depends on this, and if the | 743 | * management scheme depends on this, and if the | |
740 | * SONIC didn't follow our rule, it means we've | 744 | * SONIC didn't follow our rule, it means we've | |
741 | * misconfigured it. | 745 | * misconfigured it. | |
742 | */ | 746 | */ | |
743 | KASSERT(status & RCR_LPKT); | 747 | KASSERT(status & RCR_LPKT); | |
744 | 748 | |||
745 | /* | 749 | /* | |
746 | * Make sure the packet arrived OK. If an error occurred, | 750 | * Make sure the packet arrived OK. If an error occurred, | |
747 | * update stats and reset the descriptor. The buffer will | 751 | * update stats and reset the descriptor. The buffer will | |
748 | * be reused the next time the descriptor comes up in the | 752 | * be reused the next time the descriptor comes up in the | |
749 | * ring. | 753 | * ring. | |
750 | */ | 754 | */ | |
751 | if ((status & RCR_PRX) == 0) { | 755 | if ((status & RCR_PRX) == 0) { | |
752 | if (status & RCR_FAER) | 756 | if (status & RCR_FAER) | |
753 | printf("%s: Rx frame alignment error\n", | 757 | printf("%s: Rx frame alignment error\n", | |
754 | device_xname(sc->sc_dev)); | 758 | device_xname(sc->sc_dev)); | |
755 | else if (status & RCR_CRCR) | 759 | else if (status & RCR_CRCR) | |
756 | printf("%s: Rx CRC error\n", | 760 | printf("%s: Rx CRC error\n", | |
757 | device_xname(sc->sc_dev)); | 761 | device_xname(sc->sc_dev)); | |
758 | ifp->if_ierrors++; | 762 | if_statinc(ifp, if_ierrors); | |
759 | SONIC_INIT_RXDESC(sc, i); | 763 | SONIC_INIT_RXDESC(sc, i); | |
760 | continue; | 764 | continue; | |
761 | } | 765 | } | |
762 | 766 | |||
763 | bus_dmamap_sync(sc->sc_dmat, ds->ds_dmamap, 0, | 767 | bus_dmamap_sync(sc->sc_dmat, ds->ds_dmamap, 0, | |
764 | ds->ds_dmamap->dm_mapsize, BUS_DMASYNC_POSTREAD); | 768 | ds->ds_dmamap->dm_mapsize, BUS_DMASYNC_POSTREAD); | |
765 | 769 | |||
766 | /* | 770 | /* | |
767 | * The SONIC includes the CRC with every packet. | 771 | * The SONIC includes the CRC with every packet. | |
768 | */ | 772 | */ | |
769 | len = bytecount - ETHER_CRC_LEN; | 773 | len = bytecount - ETHER_CRC_LEN; | |
770 | 774 | |||
771 | /* | 775 | /* | |
772 | * Ok, if the chip is in 32-bit mode, then receive | 776 | * Ok, if the chip is in 32-bit mode, then receive | |
773 | * buffers must be aligned to 32-bit boundaries, | 777 | * buffers must be aligned to 32-bit boundaries, | |
774 | * which means the payload is misaligned. In this | 778 | * which means the payload is misaligned. In this | |
775 | * case, we must allocate a new mbuf, and copy the | 779 | * case, we must allocate a new mbuf, and copy the | |
776 | * packet into it, scooted forward 2 bytes to ensure | 780 | * packet into it, scooted forward 2 bytes to ensure | |
777 | * proper alignment. | 781 | * proper alignment. | |
778 | * | 782 | * | |
779 | * Note, in 16-bit mode, we can configure the SONIC | 783 | * Note, in 16-bit mode, we can configure the SONIC | |
780 | * to do what we want, and we have. | 784 | * to do what we want, and we have. | |
781 | */ | 785 | */ | |
782 | #ifndef __NO_STRICT_ALIGNMENT | 786 | #ifndef __NO_STRICT_ALIGNMENT | |
783 | if (sc->sc_32bit) { | 787 | if (sc->sc_32bit) { | |
784 | MGETHDR(m, M_DONTWAIT, MT_DATA); | 788 | MGETHDR(m, M_DONTWAIT, MT_DATA); | |
785 | if (m == NULL) | 789 | if (m == NULL) | |
786 | goto dropit; | 790 | goto dropit; | |
787 | if (len > (MHLEN - 2)) { | 791 | if (len > (MHLEN - 2)) { | |
788 | MCLGET(m, M_DONTWAIT); | 792 | MCLGET(m, M_DONTWAIT); | |
789 | if ((m->m_flags & M_EXT) == 0) { | 793 | if ((m->m_flags & M_EXT) == 0) { | |
790 | m_freem(m); | 794 | m_freem(m); | |
791 | goto dropit; | 795 | goto dropit; | |
792 | } | 796 | } | |
793 | } | 797 | } | |
794 | m->m_data += 2; | 798 | m->m_data += 2; | |
795 | /* | 799 | /* | |
796 | * Note that we use a cluster for incoming frames, | 800 | * Note that we use a cluster for incoming frames, | |
797 | * so the buffer is virtually contiguous. | 801 | * so the buffer is virtually contiguous. | |
798 | */ | 802 | */ | |
799 | memcpy(mtod(m, void *), mtod(ds->ds_mbuf, void *), | 803 | memcpy(mtod(m, void *), mtod(ds->ds_mbuf, void *), | |
800 | len); | 804 | len); | |
801 | SONIC_INIT_RXDESC(sc, i); | 805 | SONIC_INIT_RXDESC(sc, i); | |
802 | bus_dmamap_sync(sc->sc_dmat, ds->ds_dmamap, 0, | 806 | bus_dmamap_sync(sc->sc_dmat, ds->ds_dmamap, 0, | |
803 | ds->ds_dmamap->dm_mapsize, BUS_DMASYNC_PREREAD); | 807 | ds->ds_dmamap->dm_mapsize, BUS_DMASYNC_PREREAD); | |
804 | } else | 808 | } else | |
805 | #endif /* ! __NO_STRICT_ALIGNMENT */ | 809 | #endif /* ! __NO_STRICT_ALIGNMENT */ | |
806 | /* | 810 | /* | |
807 | * If the packet is small enough to fit in a single | 811 | * If the packet is small enough to fit in a single | |
808 | * header mbuf, allocate one and copy the data into | 812 | * header mbuf, allocate one and copy the data into | |
809 | * it. This greatly reduces memory consumption when | 813 | * it. This greatly reduces memory consumption when | |
810 | * we receive lots of small packets. | 814 | * we receive lots of small packets. | |
811 | */ | 815 | */ | |
812 | if (sonic_copy_small != 0 && len <= (MHLEN - 2)) { | 816 | if (sonic_copy_small != 0 && len <= (MHLEN - 2)) { | |
813 | MGETHDR(m, M_DONTWAIT, MT_DATA); | 817 | MGETHDR(m, M_DONTWAIT, MT_DATA); | |
814 | if (m == NULL) | 818 | if (m == NULL) | |
815 | goto dropit; | 819 | goto dropit; | |
816 | m->m_data += 2; | 820 | m->m_data += 2; | |
817 | /* | 821 | /* | |
818 | * Note that we use a cluster for incoming frames, | 822 | * Note that we use a cluster for incoming frames, | |
819 | * so the buffer is virtually contiguous. | 823 | * so the buffer is virtually contiguous. | |
820 | */ | 824 | */ | |
821 | memcpy(mtod(m, void *), mtod(ds->ds_mbuf, void *), | 825 | memcpy(mtod(m, void *), mtod(ds->ds_mbuf, void *), | |
822 | len); | 826 | len); | |
823 | SONIC_INIT_RXDESC(sc, i); | 827 | SONIC_INIT_RXDESC(sc, i); | |
824 | bus_dmamap_sync(sc->sc_dmat, ds->ds_dmamap, 0, | 828 | bus_dmamap_sync(sc->sc_dmat, ds->ds_dmamap, 0, | |
825 | ds->ds_dmamap->dm_mapsize, BUS_DMASYNC_PREREAD); | 829 | ds->ds_dmamap->dm_mapsize, BUS_DMASYNC_PREREAD); | |
826 | } else { | 830 | } else { | |
827 | m = ds->ds_mbuf; | 831 | m = ds->ds_mbuf; | |
828 | if (sonic_add_rxbuf(sc, i) != 0) { | 832 | if (sonic_add_rxbuf(sc, i) != 0) { | |
829 | dropit: | 833 | dropit: | |
830 | ifp->if_ierrors++; | 834 | if_statinc(ifp, if_ierrors); | |
831 | SONIC_INIT_RXDESC(sc, i); | 835 | SONIC_INIT_RXDESC(sc, i); | |
832 | bus_dmamap_sync(sc->sc_dmat, ds->ds_dmamap, 0, | 836 | bus_dmamap_sync(sc->sc_dmat, ds->ds_dmamap, 0, | |
833 | ds->ds_dmamap->dm_mapsize, | 837 | ds->ds_dmamap->dm_mapsize, | |
834 | BUS_DMASYNC_PREREAD); | 838 | BUS_DMASYNC_PREREAD); | |
835 | continue; | 839 | continue; | |
836 | } | 840 | } | |
837 | } | 841 | } | |
838 | 842 | |||
839 | m_set_rcvif(m, ifp); | 843 | m_set_rcvif(m, ifp); | |
840 | m->m_pkthdr.len = m->m_len = len; | 844 | m->m_pkthdr.len = m->m_len = len; | |
841 | 845 | |||
842 | /* Pass it on. */ | 846 | /* Pass it on. */ | |
843 | if_percpuq_enqueue(ifp->if_percpuq, m); | 847 | if_percpuq_enqueue(ifp->if_percpuq, m); | |
844 | } | 848 | } | |
845 | 849 | |||
846 | /* Update the receive pointer. */ | 850 | /* Update the receive pointer. */ | |
847 | sc->sc_rxptr = i; | 851 | sc->sc_rxptr = i; | |
848 | CSR_WRITE(sc, SONIC_RWR, SONIC_CDRRADDR(sc, SONIC_PREVRX(i))); | 852 | CSR_WRITE(sc, SONIC_RWR, SONIC_CDRRADDR(sc, SONIC_PREVRX(i))); | |
849 | } | 853 | } | |
850 | 854 | |||
851 | /* | 855 | /* | |
852 | * sonic_reset: | 856 | * sonic_reset: | |
853 | * | 857 | * | |
854 | * Perform a soft reset on the SONIC. | 858 | * Perform a soft reset on the SONIC. | |
855 | */ | 859 | */ | |
856 | void | 860 | void | |
857 | sonic_reset(struct sonic_softc *sc) | 861 | sonic_reset(struct sonic_softc *sc) | |
858 | { | 862 | { | |
859 | 863 | |||
860 | /* stop TX, RX and timer, and ensure RST is clear */ | 864 | /* stop TX, RX and timer, and ensure RST is clear */ | |
861 | CSR_WRITE(sc, SONIC_CR, CR_STP | CR_RXDIS | CR_HTX); | 865 | CSR_WRITE(sc, SONIC_CR, CR_STP | CR_RXDIS | CR_HTX); | |
862 | delay(1000); | 866 | delay(1000); | |
863 | 867 | |||
864 | CSR_WRITE(sc, SONIC_CR, CR_RST); | 868 | CSR_WRITE(sc, SONIC_CR, CR_RST); | |
865 | delay(1000); | 869 | delay(1000); | |
866 | 870 | |||
867 | /* clear all interrupts */ | 871 | /* clear all interrupts */ | |
868 | CSR_WRITE(sc, SONIC_IMR, 0); | 872 | CSR_WRITE(sc, SONIC_IMR, 0); | |
869 | CSR_WRITE(sc, SONIC_ISR, IMR_ALL); | 873 | CSR_WRITE(sc, SONIC_ISR, IMR_ALL); | |
870 | 874 | |||
871 | CSR_WRITE(sc, SONIC_CR, 0); | 875 | CSR_WRITE(sc, SONIC_CR, 0); | |
872 | delay(1000); | 876 | delay(1000); | |
873 | } | 877 | } | |
874 | 878 | |||
875 | /* | 879 | /* | |
876 | * sonic_init: [ifnet interface function] | 880 | * sonic_init: [ifnet interface function] | |
877 | * | 881 | * | |
878 | * Initialize the interface. Must be called at splnet(). | 882 | * Initialize the interface. Must be called at splnet(). | |
879 | */ | 883 | */ | |
880 | int | 884 | int | |
881 | sonic_init(struct ifnet *ifp) | 885 | sonic_init(struct ifnet *ifp) | |
882 | { | 886 | { | |
883 | struct sonic_softc *sc = ifp->if_softc; | 887 | struct sonic_softc *sc = ifp->if_softc; | |
884 | struct sonic_descsoft *ds; | 888 | struct sonic_descsoft *ds; | |
885 | int i, error = 0; | 889 | int i, error = 0; | |
886 | uint16_t reg; | 890 | uint16_t reg; | |
887 | 891 | |||
888 | /* | 892 | /* | |
889 | * Cancel any pending I/O. | 893 | * Cancel any pending I/O. | |
890 | */ | 894 | */ | |
891 | sonic_stop(ifp, 0); | 895 | sonic_stop(ifp, 0); | |
892 | 896 | |||
893 | /* | 897 | /* | |
894 | * Reset the SONIC to a known state. | 898 | * Reset the SONIC to a known state. | |
895 | */ | 899 | */ | |
896 | sonic_reset(sc); | 900 | sonic_reset(sc); | |
897 | 901 | |||
898 | /* | 902 | /* | |
899 | * Bring the SONIC into reset state, and program the DCR. | 903 | * Bring the SONIC into reset state, and program the DCR. | |
900 | * | 904 | * | |
901 | * Note: We don't bother optimizing the transmit and receive | 905 | * Note: We don't bother optimizing the transmit and receive | |
902 | * thresholds, here. TFT/RFT values should be set in MD attachments. | 906 | * thresholds, here. TFT/RFT values should be set in MD attachments. | |
903 | */ | 907 | */ | |
904 | reg = sc->sc_dcr; | 908 | reg = sc->sc_dcr; | |
905 | if (sc->sc_32bit) | 909 | if (sc->sc_32bit) | |
906 | reg |= DCR_DW; | 910 | reg |= DCR_DW; | |
907 | CSR_WRITE(sc, SONIC_CR, CR_RST); | 911 | CSR_WRITE(sc, SONIC_CR, CR_RST); | |
908 | CSR_WRITE(sc, SONIC_DCR, reg); | 912 | CSR_WRITE(sc, SONIC_DCR, reg); | |
909 | CSR_WRITE(sc, SONIC_DCR2, sc->sc_dcr2); | 913 | CSR_WRITE(sc, SONIC_DCR2, sc->sc_dcr2); | |
910 | CSR_WRITE(sc, SONIC_CR, 0); | 914 | CSR_WRITE(sc, SONIC_CR, 0); | |
911 | 915 | |||
912 | /* | 916 | /* | |
913 | * Initialize the transmit descriptors. | 917 | * Initialize the transmit descriptors. | |
914 | */ | 918 | */ | |
915 | if (sc->sc_32bit) { | 919 | if (sc->sc_32bit) { | |
916 | for (i = 0; i < SONIC_NTXDESC; i++) { | 920 | for (i = 0; i < SONIC_NTXDESC; i++) { | |
917 | memset(&sc->sc_tda32[i], 0, sizeof(struct sonic_tda32)); | 921 | memset(&sc->sc_tda32[i], 0, sizeof(struct sonic_tda32)); | |
918 | SONIC_CDTXSYNC32(sc, i, | 922 | SONIC_CDTXSYNC32(sc, i, | |
919 | BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); | 923 | BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); | |
920 | } | 924 | } | |
921 | } else { | 925 | } else { | |
922 | for (i = 0; i < SONIC_NTXDESC; i++) { | 926 | for (i = 0; i < SONIC_NTXDESC; i++) { | |
923 | memset(&sc->sc_tda16[i], 0, sizeof(struct sonic_tda16)); | 927 | memset(&sc->sc_tda16[i], 0, sizeof(struct sonic_tda16)); | |
924 | SONIC_CDTXSYNC16(sc, i, | 928 | SONIC_CDTXSYNC16(sc, i, | |
925 | BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); | 929 | BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); | |
926 | } | 930 | } | |
927 | } | 931 | } | |
928 | sc->sc_txpending = 0; | 932 | sc->sc_txpending = 0; | |
929 | sc->sc_txdirty = 0; | 933 | sc->sc_txdirty = 0; | |
930 | sc->sc_txlast = SONIC_NTXDESC - 1; | 934 | sc->sc_txlast = SONIC_NTXDESC - 1; | |
931 | 935 | |||
932 | /* | 936 | /* | |
933 | * Initialize the receive descriptor ring. | 937 | * Initialize the receive descriptor ring. | |
934 | */ | 938 | */ | |
935 | for (i = 0; i < SONIC_NRXDESC; i++) { | 939 | for (i = 0; i < SONIC_NRXDESC; i++) { | |
936 | ds = &sc->sc_rxsoft[i]; | 940 | ds = &sc->sc_rxsoft[i]; | |
937 | if (ds->ds_mbuf == NULL) { | 941 | if (ds->ds_mbuf == NULL) { | |
938 | if ((error = sonic_add_rxbuf(sc, i)) != 0) { | 942 | if ((error = sonic_add_rxbuf(sc, i)) != 0) { | |
939 | printf("%s: unable to allocate or map Rx " | 943 | printf("%s: unable to allocate or map Rx " | |
940 | "buffer %d, error = %d\n", | 944 | "buffer %d, error = %d\n", | |
941 | device_xname(sc->sc_dev), i, error); | 945 | device_xname(sc->sc_dev), i, error); | |
942 | /* | 946 | /* | |
943 | * XXX Should attempt to run with fewer receive | 947 | * XXX Should attempt to run with fewer receive | |
944 | * XXX buffers instead of just failing. | 948 | * XXX buffers instead of just failing. | |
945 | */ | 949 | */ | |
946 | sonic_rxdrain(sc); | 950 | sonic_rxdrain(sc); | |
947 | goto out; | 951 | goto out; | |
948 | } | 952 | } | |
949 | } else | 953 | } else | |
950 | SONIC_INIT_RXDESC(sc, i); | 954 | SONIC_INIT_RXDESC(sc, i); | |
951 | } | 955 | } | |
952 | sc->sc_rxptr = 0; | 956 | sc->sc_rxptr = 0; | |
953 | 957 | |||
954 | /* Give the transmit ring to the SONIC. */ | 958 | /* Give the transmit ring to the SONIC. */ | |
955 | CSR_WRITE(sc, SONIC_UTDAR, (SONIC_CDTXADDR(sc, 0) >> 16) & 0xffff); | 959 | CSR_WRITE(sc, SONIC_UTDAR, (SONIC_CDTXADDR(sc, 0) >> 16) & 0xffff); | |
956 | CSR_WRITE(sc, SONIC_CTDAR, SONIC_CDTXADDR(sc, 0) & 0xffff); | 960 | CSR_WRITE(sc, SONIC_CTDAR, SONIC_CDTXADDR(sc, 0) & 0xffff); | |
957 | 961 | |||
958 | /* Give the receive descriptor ring to the SONIC. */ | 962 | /* Give the receive descriptor ring to the SONIC. */ | |
959 | CSR_WRITE(sc, SONIC_URDAR, (SONIC_CDRXADDR(sc, 0) >> 16) & 0xffff); | 963 | CSR_WRITE(sc, SONIC_URDAR, (SONIC_CDRXADDR(sc, 0) >> 16) & 0xffff); | |
960 | CSR_WRITE(sc, SONIC_CRDAR, SONIC_CDRXADDR(sc, 0) & 0xffff); | 964 | CSR_WRITE(sc, SONIC_CRDAR, SONIC_CDRXADDR(sc, 0) & 0xffff); | |
961 | 965 | |||
962 | /* Give the receive buffer ring to the SONIC. */ | 966 | /* Give the receive buffer ring to the SONIC. */ | |
963 | CSR_WRITE(sc, SONIC_URRAR, (SONIC_CDRRADDR(sc, 0) >> 16) & 0xffff); | 967 | CSR_WRITE(sc, SONIC_URRAR, (SONIC_CDRRADDR(sc, 0) >> 16) & 0xffff); | |
964 | CSR_WRITE(sc, SONIC_RSAR, SONIC_CDRRADDR(sc, 0) & 0xffff); | 968 | CSR_WRITE(sc, SONIC_RSAR, SONIC_CDRRADDR(sc, 0) & 0xffff); | |
965 | if (sc->sc_32bit) | 969 | if (sc->sc_32bit) | |
966 | CSR_WRITE(sc, SONIC_REAR, | 970 | CSR_WRITE(sc, SONIC_REAR, | |
967 | (SONIC_CDRRADDR(sc, SONIC_NRXDESC - 1) + | 971 | (SONIC_CDRRADDR(sc, SONIC_NRXDESC - 1) + | |
968 | sizeof(struct sonic_rra32)) & 0xffff); | 972 | sizeof(struct sonic_rra32)) & 0xffff); | |
969 | else | 973 | else | |
970 | CSR_WRITE(sc, SONIC_REAR, | 974 | CSR_WRITE(sc, SONIC_REAR, | |
971 | (SONIC_CDRRADDR(sc, SONIC_NRXDESC - 1) + | 975 | (SONIC_CDRRADDR(sc, SONIC_NRXDESC - 1) + | |
972 | sizeof(struct sonic_rra16)) & 0xffff); | 976 | sizeof(struct sonic_rra16)) & 0xffff); | |
973 | CSR_WRITE(sc, SONIC_RRR, SONIC_CDRRADDR(sc, 0) & 0xffff); | 977 | CSR_WRITE(sc, SONIC_RRR, SONIC_CDRRADDR(sc, 0) & 0xffff); | |
974 | CSR_WRITE(sc, SONIC_RWR, SONIC_CDRRADDR(sc, SONIC_NRXDESC - 1)); | 978 | CSR_WRITE(sc, SONIC_RWR, SONIC_CDRRADDR(sc, SONIC_NRXDESC - 1)); | |
975 | 979 | |||
976 | /* | 980 | /* | |
977 | * Set the End-Of-Buffer counter such that only one packet | 981 | * Set the End-Of-Buffer counter such that only one packet | |
978 | * will be placed into each buffer we provide. Note we are | 982 | * will be placed into each buffer we provide. Note we are | |
979 | * following the recommendation of section 3.4.4 of the manual | 983 | * following the recommendation of section 3.4.4 of the manual | |
980 | * here, and have "lengthened" the receive buffers accordingly. | 984 | * here, and have "lengthened" the receive buffers accordingly. | |
981 | */ | 985 | */ | |
982 | if (sc->sc_32bit) | 986 | if (sc->sc_32bit) | |
983 | CSR_WRITE(sc, SONIC_EOBC, (ETHER_MAX_LEN + 2) / 2); | 987 | CSR_WRITE(sc, SONIC_EOBC, (ETHER_MAX_LEN + 2) / 2); | |
984 | else | 988 | else | |
985 | CSR_WRITE(sc, SONIC_EOBC, (ETHER_MAX_LEN / 2)); | 989 | CSR_WRITE(sc, SONIC_EOBC, (ETHER_MAX_LEN / 2)); | |
986 | 990 | |||
987 | /* Reset the receive sequence counter. */ | 991 | /* Reset the receive sequence counter. */ | |
988 | CSR_WRITE(sc, SONIC_RSC, 0); | 992 | CSR_WRITE(sc, SONIC_RSC, 0); | |
989 | 993 | |||
990 | /* Clear the tally registers. */ | 994 | /* Clear the tally registers. */ | |
991 | CSR_WRITE(sc, SONIC_CRCETC, 0xffff); | 995 | CSR_WRITE(sc, SONIC_CRCETC, 0xffff); | |
992 | CSR_WRITE(sc, SONIC_FAET, 0xffff); | 996 | CSR_WRITE(sc, SONIC_FAET, 0xffff); | |
993 | CSR_WRITE(sc, SONIC_MPT, 0xffff); | 997 | CSR_WRITE(sc, SONIC_MPT, 0xffff); | |
994 | 998 | |||
995 | /* Set the receive filter. */ | 999 | /* Set the receive filter. */ | |
996 | sonic_set_filter(sc); | 1000 | sonic_set_filter(sc); | |
997 | 1001 | |||
998 | /* | 1002 | /* | |
999 | * Set the interrupt mask register. | 1003 | * Set the interrupt mask register. | |
1000 | */ | 1004 | */ | |
1001 | sc->sc_imr = IMR_RFO | IMR_RBA | IMR_RBE | IMR_RDE | | 1005 | sc->sc_imr = IMR_RFO | IMR_RBA | IMR_RBE | IMR_RDE | | |
1002 | IMR_TXER | IMR_PTX | IMR_PRX; | 1006 | IMR_TXER | IMR_PTX | IMR_PRX; | |
1003 | CSR_WRITE(sc, SONIC_IMR, sc->sc_imr); | 1007 | CSR_WRITE(sc, SONIC_IMR, sc->sc_imr); | |
1004 | 1008 | |||
1005 | /* | 1009 | /* | |
1006 | * Start the receive process in motion. Note, we don't | 1010 | * Start the receive process in motion. Note, we don't | |
1007 | * start the transmit process until we actually try to | 1011 | * start the transmit process until we actually try to | |
1008 | * transmit packets. | 1012 | * transmit packets. | |
1009 | */ | 1013 | */ | |
1010 | CSR_WRITE(sc, SONIC_CR, CR_RXEN | CR_RRRA); | 1014 | CSR_WRITE(sc, SONIC_CR, CR_RXEN | CR_RRRA); | |
1011 | 1015 | |||
1012 | /* | 1016 | /* | |
1013 | * ...all done! | 1017 | * ...all done! | |
1014 | */ | 1018 | */ | |
1015 | ifp->if_flags |= IFF_RUNNING; | 1019 | ifp->if_flags |= IFF_RUNNING; | |
1016 | ifp->if_flags &= ~IFF_OACTIVE; | 1020 | ifp->if_flags &= ~IFF_OACTIVE; | |
1017 | 1021 | |||
1018 | out: | 1022 | out: | |
1019 | if (error) | 1023 | if (error) | |
1020 | printf("%s: interface not running\n", device_xname(sc->sc_dev)); | 1024 | printf("%s: interface not running\n", device_xname(sc->sc_dev)); | |
1021 | return error; | 1025 | return error; | |
1022 | } | 1026 | } | |
1023 | 1027 | |||
1024 | /* | 1028 | /* | |
1025 | * sonic_rxdrain: | 1029 | * sonic_rxdrain: | |
1026 | * | 1030 | * | |
1027 | * Drain the receive queue. | 1031 | * Drain the receive queue. | |
1028 | */ | 1032 | */ | |
1029 | void | 1033 | void | |
1030 | sonic_rxdrain(struct sonic_softc *sc) | 1034 | sonic_rxdrain(struct sonic_softc *sc) | |
1031 | { | 1035 | { | |
1032 | struct sonic_descsoft *ds; | 1036 | struct sonic_descsoft *ds; | |
1033 | int i; | 1037 | int i; | |
1034 | 1038 | |||
1035 | for (i = 0; i < SONIC_NRXDESC; i++) { | 1039 | for (i = 0; i < SONIC_NRXDESC; i++) { | |
1036 | ds = &sc->sc_rxsoft[i]; | 1040 | ds = &sc->sc_rxsoft[i]; | |
1037 | if (ds->ds_mbuf != NULL) { | 1041 | if (ds->ds_mbuf != NULL) { | |
1038 | bus_dmamap_unload(sc->sc_dmat, ds->ds_dmamap); | 1042 | bus_dmamap_unload(sc->sc_dmat, ds->ds_dmamap); | |
1039 | m_freem(ds->ds_mbuf); | 1043 | m_freem(ds->ds_mbuf); | |
1040 | ds->ds_mbuf = NULL; | 1044 | ds->ds_mbuf = NULL; | |
1041 | } | 1045 | } | |
1042 | } | 1046 | } | |
1043 | } | 1047 | } | |
1044 | 1048 | |||
1045 | /* | 1049 | /* | |
1046 | * sonic_stop: [ifnet interface function] | 1050 | * sonic_stop: [ifnet interface function] | |
1047 | * | 1051 | * | |
1048 | * Stop transmission on the interface. | 1052 | * Stop transmission on the interface. | |
1049 | */ | 1053 | */ | |
1050 | void | 1054 | void | |
1051 | sonic_stop(struct ifnet *ifp, int disable) | 1055 | sonic_stop(struct ifnet *ifp, int disable) | |
1052 | { | 1056 | { | |
1053 | struct sonic_softc *sc = ifp->if_softc; | 1057 | struct sonic_softc *sc = ifp->if_softc; | |
1054 | struct sonic_descsoft *ds; | 1058 | struct sonic_descsoft *ds; | |
1055 | int i; | 1059 | int i; | |
1056 | 1060 | |||
1057 | /* | 1061 | /* | |
1058 | * Disable interrupts. | 1062 | * Disable interrupts. | |
1059 | */ | 1063 | */ | |
1060 | CSR_WRITE(sc, SONIC_IMR, 0); | 1064 | CSR_WRITE(sc, SONIC_IMR, 0); | |
1061 | 1065 | |||
1062 | /* | 1066 | /* | |
1063 | * Stop the transmitter, receiver, and timer. | 1067 | * Stop the transmitter, receiver, and timer. | |
1064 | */ | 1068 | */ | |
1065 | CSR_WRITE(sc, SONIC_CR, CR_HTX | CR_RXDIS | CR_STP); | 1069 | CSR_WRITE(sc, SONIC_CR, CR_HTX | CR_RXDIS | CR_STP); | |
1066 | for (i = 0; i < 1000; i++) { | 1070 | for (i = 0; i < 1000; i++) { | |
1067 | if ((CSR_READ(sc, SONIC_CR) & (CR_TXP | CR_RXEN | CR_ST)) == 0) | 1071 | if ((CSR_READ(sc, SONIC_CR) & (CR_TXP | CR_RXEN | CR_ST)) == 0) | |
1068 | break; | 1072 | break; | |
1069 | delay(2); | 1073 | delay(2); | |
1070 | } | 1074 | } | |
1071 | if ((CSR_READ(sc, SONIC_CR) & (CR_TXP | CR_RXEN | CR_ST)) != 0) | 1075 | if ((CSR_READ(sc, SONIC_CR) & (CR_TXP | CR_RXEN | CR_ST)) != 0) | |
1072 | printf("%s: SONIC failed to stop\n", device_xname(sc->sc_dev)); | 1076 | printf("%s: SONIC failed to stop\n", device_xname(sc->sc_dev)); | |
1073 | 1077 | |||
1074 | /* | 1078 | /* | |
1075 | * Release any queued transmit buffers. | 1079 | * Release any queued transmit buffers. | |
1076 | */ | 1080 | */ | |
1077 | for (i = 0; i < SONIC_NTXDESC; i++) { | 1081 | for (i = 0; i < SONIC_NTXDESC; i++) { | |
1078 | ds = &sc->sc_txsoft[i]; | 1082 | ds = &sc->sc_txsoft[i]; | |
1079 | if (ds->ds_mbuf != NULL) { | 1083 | if (ds->ds_mbuf != NULL) { | |
1080 | bus_dmamap_unload(sc->sc_dmat, ds->ds_dmamap); | 1084 | bus_dmamap_unload(sc->sc_dmat, ds->ds_dmamap); | |
1081 | m_freem(ds->ds_mbuf); | 1085 | m_freem(ds->ds_mbuf); | |
1082 | ds->ds_mbuf = NULL; | 1086 | ds->ds_mbuf = NULL; | |
1083 | } | 1087 | } | |
1084 | } | 1088 | } | |
1085 | 1089 | |||
1086 | /* | 1090 | /* | |
1087 | * Mark the interface down and cancel the watchdog timer. | 1091 | * Mark the interface down and cancel the watchdog timer. | |
1088 | */ | 1092 | */ | |
1089 | ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); | 1093 | ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); | |
1090 | ifp->if_timer = 0; | 1094 | ifp->if_timer = 0; | |
1091 | 1095 | |||
1092 | if (disable) | 1096 | if (disable) | |
1093 | sonic_rxdrain(sc); | 1097 | sonic_rxdrain(sc); | |
1094 | } | 1098 | } | |
1095 | 1099 | |||
1096 | /* | 1100 | /* | |
1097 | * sonic_add_rxbuf: | 1101 | * sonic_add_rxbuf: | |
1098 | * | 1102 | * | |
1099 | * Add a receive buffer to the indicated descriptor. | 1103 | * Add a receive buffer to the indicated descriptor. | |
1100 | */ | 1104 | */ | |
1101 | int | 1105 | int | |
1102 | sonic_add_rxbuf(struct sonic_softc *sc, int idx) | 1106 | sonic_add_rxbuf(struct sonic_softc *sc, int idx) | |
1103 | { | 1107 | { | |
1104 | struct sonic_descsoft *ds = &sc->sc_rxsoft[idx]; | 1108 | struct sonic_descsoft *ds = &sc->sc_rxsoft[idx]; | |
1105 | struct mbuf *m; | 1109 | struct mbuf *m; | |
1106 | int error; | 1110 | int error; | |
1107 | 1111 | |||
1108 | MGETHDR(m, M_DONTWAIT, MT_DATA); | 1112 | MGETHDR(m, M_DONTWAIT, MT_DATA); | |
1109 | if (m == NULL) | 1113 | if (m == NULL) | |
1110 | return ENOBUFS; | 1114 | return ENOBUFS; | |
1111 | 1115 | |||
1112 | MCLGET(m, M_DONTWAIT); | 1116 | MCLGET(m, M_DONTWAIT); | |
1113 | if ((m->m_flags & M_EXT) == 0) { | 1117 | if ((m->m_flags & M_EXT) == 0) { | |
1114 | m_freem(m); | 1118 | m_freem(m); | |
1115 | return ENOBUFS; | 1119 | return ENOBUFS; | |
1116 | } | 1120 | } | |
1117 | 1121 | |||
1118 | if (ds->ds_mbuf != NULL) | 1122 | if (ds->ds_mbuf != NULL) | |
1119 | bus_dmamap_unload(sc->sc_dmat, ds->ds_dmamap); | 1123 | bus_dmamap_unload(sc->sc_dmat, ds->ds_dmamap); | |
1120 | 1124 | |||
1121 | ds->ds_mbuf = m; | 1125 | ds->ds_mbuf = m; | |
1122 | 1126 | |||
1123 | error = bus_dmamap_load(sc->sc_dmat, ds->ds_dmamap, | 1127 | error = bus_dmamap_load(sc->sc_dmat, ds->ds_dmamap, | |
1124 | m->m_ext.ext_buf, m->m_ext.ext_size, NULL, | 1128 | m->m_ext.ext_buf, m->m_ext.ext_size, NULL, | |
1125 | BUS_DMA_READ | BUS_DMA_NOWAIT); | 1129 | BUS_DMA_READ | BUS_DMA_NOWAIT); | |
1126 | if (error) { | 1130 | if (error) { | |
1127 | printf("%s: can't load rx DMA map %d, error = %d\n", | 1131 | printf("%s: can't load rx DMA map %d, error = %d\n", | |
1128 | device_xname(sc->sc_dev), idx, error); | 1132 | device_xname(sc->sc_dev), idx, error); | |
1129 | panic("sonic_add_rxbuf"); /* XXX */ | 1133 | panic("sonic_add_rxbuf"); /* XXX */ | |
1130 | } | 1134 | } | |
1131 | 1135 | |||
1132 | bus_dmamap_sync(sc->sc_dmat, ds->ds_dmamap, 0, | 1136 | bus_dmamap_sync(sc->sc_dmat, ds->ds_dmamap, 0, | |
1133 | ds->ds_dmamap->dm_mapsize, BUS_DMASYNC_PREREAD); | 1137 | ds->ds_dmamap->dm_mapsize, BUS_DMASYNC_PREREAD); | |
1134 | 1138 | |||
1135 | SONIC_INIT_RXDESC(sc, idx); | 1139 | SONIC_INIT_RXDESC(sc, idx); | |
1136 | 1140 | |||
1137 | return 0; | 1141 | return 0; | |
1138 | } | 1142 | } | |
1139 | 1143 | |||
1140 | static void | 1144 | static void | |
1141 | sonic_set_camentry(struct sonic_softc *sc, int entry, const uint8_t *enaddr) | 1145 | sonic_set_camentry(struct sonic_softc *sc, int entry, const uint8_t *enaddr) | |
1142 | { | 1146 | { | |
1143 | 1147 | |||
1144 | if (sc->sc_32bit) { | 1148 | if (sc->sc_32bit) { | |
1145 | struct sonic_cda32 *cda = &sc->sc_cda32[entry]; | 1149 | struct sonic_cda32 *cda = &sc->sc_cda32[entry]; | |
1146 | 1150 | |||
1147 | cda->cda_entry = htosonic32(sc, entry); | 1151 | cda->cda_entry = htosonic32(sc, entry); | |
1148 | cda->cda_addr0 = htosonic32(sc, enaddr[0] | (enaddr[1] << 8)); | 1152 | cda->cda_addr0 = htosonic32(sc, enaddr[0] | (enaddr[1] << 8)); | |
1149 | cda->cda_addr1 = htosonic32(sc, enaddr[2] | (enaddr[3] << 8)); | 1153 | cda->cda_addr1 = htosonic32(sc, enaddr[2] | (enaddr[3] << 8)); | |
1150 | cda->cda_addr2 = htosonic32(sc, enaddr[4] | (enaddr[5] << 8)); | 1154 | cda->cda_addr2 = htosonic32(sc, enaddr[4] | (enaddr[5] << 8)); | |
1151 | } else { | 1155 | } else { | |
1152 | struct sonic_cda16 *cda = &sc->sc_cda16[entry]; | 1156 | struct sonic_cda16 *cda = &sc->sc_cda16[entry]; | |
1153 | 1157 | |||
1154 | cda->cda_entry = htosonic16(sc, entry); | 1158 | cda->cda_entry = htosonic16(sc, entry); | |
1155 | cda->cda_addr0 = htosonic16(sc, enaddr[0] | (enaddr[1] << 8)); | 1159 | cda->cda_addr0 = htosonic16(sc, enaddr[0] | (enaddr[1] << 8)); | |
1156 | cda->cda_addr1 = htosonic16(sc, enaddr[2] | (enaddr[3] << 8)); | 1160 | cda->cda_addr1 = htosonic16(sc, enaddr[2] | (enaddr[3] << 8)); | |
1157 | cda->cda_addr2 = htosonic16(sc, enaddr[4] | (enaddr[5] << 8)); | 1161 | cda->cda_addr2 = htosonic16(sc, enaddr[4] | (enaddr[5] << 8)); | |
1158 | } | 1162 | } | |
1159 | } | 1163 | } | |
1160 | 1164 | |||
1161 | /* | 1165 | /* | |
1162 | * sonic_set_filter: | 1166 | * sonic_set_filter: | |
1163 | * | 1167 | * | |
1164 | * Set the SONIC receive filter. | 1168 | * Set the SONIC receive filter. | |
1165 | */ | 1169 | */ | |
1166 | void | 1170 | void | |
1167 | sonic_set_filter(struct sonic_softc *sc) | 1171 | sonic_set_filter(struct sonic_softc *sc) | |
1168 | { | 1172 | { | |
1169 | struct ethercom *ec = &sc->sc_ethercom; | 1173 | struct ethercom *ec = &sc->sc_ethercom; | |
1170 | struct ifnet *ifp = &sc->sc_ethercom.ec_if; | 1174 | struct ifnet *ifp = &sc->sc_ethercom.ec_if; | |
1171 | struct ether_multi *enm; | 1175 | struct ether_multi *enm; | |
1172 | struct ether_multistep step; | 1176 | struct ether_multistep step; | |
1173 | int i, entry = 0; | 1177 | int i, entry = 0; | |
1174 | uint16_t camvalid = 0; | 1178 | uint16_t camvalid = 0; | |
1175 | uint16_t rcr = 0; | 1179 | uint16_t rcr = 0; | |
1176 | 1180 | |||
1177 | if (ifp->if_flags & IFF_BROADCAST) | 1181 | if (ifp->if_flags & IFF_BROADCAST) | |
1178 | rcr |= RCR_BRD; | 1182 | rcr |= RCR_BRD; | |
1179 | 1183 | |||
1180 | if (ifp->if_flags & IFF_PROMISC) { | 1184 | if (ifp->if_flags & IFF_PROMISC) { | |
1181 | rcr |= RCR_PRO; | 1185 | rcr |= RCR_PRO; | |
1182 | goto allmulti; | 1186 | goto allmulti; | |
1183 | } | 1187 | } | |
1184 | 1188 | |||
1185 | /* Put our station address in the first CAM slot. */ | 1189 | /* Put our station address in the first CAM slot. */ | |
1186 | sonic_set_camentry(sc, entry, CLLADDR(ifp->if_sadl)); | 1190 | sonic_set_camentry(sc, entry, CLLADDR(ifp->if_sadl)); | |
1187 | camvalid |= (1U << entry); | 1191 | camvalid |= (1U << entry); | |
1188 | entry++; | 1192 | entry++; | |
1189 | 1193 | |||
1190 | /* Add the multicast addresses to the CAM. */ | 1194 | /* Add the multicast addresses to the CAM. */ | |
1191 | ETHER_LOCK(ec); | 1195 | ETHER_LOCK(ec); | |
1192 | ETHER_FIRST_MULTI(step, ec, enm); | 1196 | ETHER_FIRST_MULTI(step, ec, enm); | |
1193 | while (enm != NULL) { | 1197 | while (enm != NULL) { | |
1194 | if (memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) { | 1198 | if (memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) { | |
1195 | /* | 1199 | /* | |
1196 | * We must listen to a range of multicast addresses. | 1200 | * We must listen to a range of multicast addresses. | |
1197 | * The only way to do this on the SONIC is to enable | 1201 | * The only way to do this on the SONIC is to enable | |
1198 | * reception of all multicast packets. | 1202 | * reception of all multicast packets. | |
1199 | */ | 1203 | */ | |
1200 | ETHER_UNLOCK(ec); | 1204 | ETHER_UNLOCK(ec); | |
1201 | goto allmulti; | 1205 | goto allmulti; | |
1202 | } | 1206 | } | |
1203 | 1207 | |||
1204 | if (entry == SONIC_NCAMENT) { | 1208 | if (entry == SONIC_NCAMENT) { | |
1205 | /* | 1209 | /* | |
1206 | * Out of CAM slots. Have to enable reception | 1210 | * Out of CAM slots. Have to enable reception | |
1207 | * of all multicast addresses. | 1211 | * of all multicast addresses. | |
1208 | */ | 1212 | */ | |
1209 | ETHER_UNLOCK(ec); | 1213 | ETHER_UNLOCK(ec); | |
1210 | goto allmulti; | 1214 | goto allmulti; | |
1211 | } | 1215 | } | |
1212 | 1216 | |||
1213 | sonic_set_camentry(sc, entry, enm->enm_addrlo); | 1217 | sonic_set_camentry(sc, entry, enm->enm_addrlo); | |
1214 | camvalid |= (1U << entry); | 1218 | camvalid |= (1U << entry); | |
1215 | entry++; | 1219 | entry++; | |
1216 | 1220 | |||
1217 | ETHER_NEXT_MULTI(step, enm); | 1221 | ETHER_NEXT_MULTI(step, enm); | |
1218 | } | 1222 | } | |
1219 | ETHER_UNLOCK(ec); | 1223 | ETHER_UNLOCK(ec); | |
1220 | 1224 | |||
1221 | ifp->if_flags &= ~IFF_ALLMULTI; | 1225 | ifp->if_flags &= ~IFF_ALLMULTI; | |
1222 | goto setit; | 1226 | goto setit; | |
1223 | 1227 | |||
1224 | allmulti: | 1228 | allmulti: | |
1225 | /* Use only the first CAM slot (station address). */ | 1229 | /* Use only the first CAM slot (station address). */ | |
1226 | camvalid = 0x0001; | 1230 | camvalid = 0x0001; | |
1227 | entry = 1; | 1231 | entry = 1; | |
1228 | rcr |= RCR_AMC; | 1232 | rcr |= RCR_AMC; | |
1229 | 1233 | |||
1230 | setit: | 1234 | setit: | |
1231 | /* set mask for the CAM Enable register */ | 1235 | /* set mask for the CAM Enable register */ | |
1232 | if (sc->sc_32bit) { | 1236 | if (sc->sc_32bit) { | |
1233 | if (entry == SONIC_NCAMENT) | 1237 | if (entry == SONIC_NCAMENT) | |
1234 | sc->sc_cdaenable32 = htosonic32(sc, camvalid); | 1238 | sc->sc_cdaenable32 = htosonic32(sc, camvalid); | |
1235 | else | 1239 | else | |
1236 | sc->sc_cda32[entry].cda_entry = | 1240 | sc->sc_cda32[entry].cda_entry = | |
1237 | htosonic32(sc, camvalid); | 1241 | htosonic32(sc, camvalid); | |
1238 | } else { | 1242 | } else { | |
1239 | if (entry == SONIC_NCAMENT) | 1243 | if (entry == SONIC_NCAMENT) | |
1240 | sc->sc_cdaenable16 = htosonic16(sc, camvalid); | 1244 | sc->sc_cdaenable16 = htosonic16(sc, camvalid); | |
1241 | else | 1245 | else | |
1242 | sc->sc_cda16[entry].cda_entry = | 1246 | sc->sc_cda16[entry].cda_entry = | |
1243 | htosonic16(sc, camvalid); | 1247 | htosonic16(sc, camvalid); | |
1244 | } | 1248 | } | |
1245 | 1249 | |||
1246 | /* Load the CAM. */ | 1250 | /* Load the CAM. */ | |
1247 | SONIC_CDCAMSYNC(sc, BUS_DMASYNC_PREWRITE); | 1251 | SONIC_CDCAMSYNC(sc, BUS_DMASYNC_PREWRITE); | |
1248 | CSR_WRITE(sc, SONIC_CDP, SONIC_CDCAMADDR(sc) & 0xffff); | 1252 | CSR_WRITE(sc, SONIC_CDP, SONIC_CDCAMADDR(sc) & 0xffff); | |
1249 | CSR_WRITE(sc, SONIC_CDC, entry); | 1253 | CSR_WRITE(sc, SONIC_CDC, entry); | |
1250 | CSR_WRITE(sc, SONIC_CR, CR_LCAM); | 1254 | CSR_WRITE(sc, SONIC_CR, CR_LCAM); | |
1251 | for (i = 0; i < 10000; i++) { | 1255 | for (i = 0; i < 10000; i++) { | |
1252 | if ((CSR_READ(sc, SONIC_CR) & CR_LCAM) == 0) | 1256 | if ((CSR_READ(sc, SONIC_CR) & CR_LCAM) == 0) | |
1253 | break; | 1257 | break; | |
1254 | delay(2); | 1258 | delay(2); | |
1255 | } | 1259 | } | |
1256 | if (CSR_READ(sc, SONIC_CR) & CR_LCAM) | 1260 | if (CSR_READ(sc, SONIC_CR) & CR_LCAM) | |
1257 | printf("%s: CAM load failed\n", device_xname(sc->sc_dev)); | 1261 | printf("%s: CAM load failed\n", device_xname(sc->sc_dev)); | |
1258 | SONIC_CDCAMSYNC(sc, BUS_DMASYNC_POSTWRITE); | 1262 | SONIC_CDCAMSYNC(sc, BUS_DMASYNC_POSTWRITE); | |
1259 | 1263 | |||
1260 | /* Set the receive control register. */ | 1264 | /* Set the receive control register. */ | |
1261 | CSR_WRITE(sc, SONIC_RCR, rcr); | 1265 | CSR_WRITE(sc, SONIC_RCR, rcr); | |
1262 | } | 1266 | } |
--- src/sys/dev/ic/dwc_gmac.c 2019/10/19 06:40:20 1.68
+++ src/sys/dev/ic/dwc_gmac.c 2020/01/29 14:14:55 1.69
@@ -1,1740 +1,1740 @@ | @@ -1,1740 +1,1740 @@ | |||
1 | /* $NetBSD: dwc_gmac.c,v 1.68 2019/10/19 06:40:20 tnn Exp $ */ | 1 | /* $NetBSD: dwc_gmac.c,v 1.69 2020/01/29 14:14:55 thorpej Exp $ */ | |
2 | 2 | |||
3 | /*- | 3 | /*- | |
4 | * Copyright (c) 2013, 2014 The NetBSD Foundation, Inc. | 4 | * Copyright (c) 2013, 2014 The NetBSD Foundation, Inc. | |
5 | * All rights reserved. | 5 | * All rights reserved. | |
6 | * | 6 | * | |
7 | * This code is derived from software contributed to The NetBSD Foundation | 7 | * This code is derived from software contributed to The NetBSD Foundation | |
8 | * by Matt Thomas of 3am Software Foundry and Martin Husemann. | 8 | * by Matt Thomas of 3am Software Foundry and Martin Husemann. | |
9 | * | 9 | * | |
10 | * Redistribution and use in source and binary forms, with or without | 10 | * Redistribution and use in source and binary forms, with or without | |
11 | * modification, are permitted provided that the following conditions | 11 | * modification, are permitted provided that the following conditions | |
12 | * are met: | 12 | * are met: | |
13 | * 1. Redistributions of source code must retain the above copyright | 13 | * 1. Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | 14 | * notice, this list of conditions and the following disclaimer. | |
15 | * 2. Redistributions in binary form must reproduce the above copyright | 15 | * 2. Redistributions in binary form must reproduce the above copyright | |
16 | * notice, this list of conditions and the following disclaimer in the | 16 | * notice, this list of conditions and the following disclaimer in the | |
17 | * documentation and/or other materials provided with the distribution. | 17 | * documentation and/or other materials provided with the distribution. | |
18 | * | 18 | * | |
19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | 19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | |
20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | 20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | |
21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | 21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | 22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | |
23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | 23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | 24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | 27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
29 | * POSSIBILITY OF SUCH DAMAGE. | 29 | * POSSIBILITY OF SUCH DAMAGE. | |
30 | */ | 30 | */ | |
31 | 31 | |||
32 | /* | 32 | /* | |
33 | * This driver supports the Synopsis Designware GMAC core, as found | 33 | * This driver supports the Synopsis Designware GMAC core, as found | |
34 | * on Allwinner A20 cores and others. | 34 | * on Allwinner A20 cores and others. | |
35 | * | 35 | * | |
36 | * Real documentation seems to not be available, the marketing product | 36 | * Real documentation seems to not be available, the marketing product | |
37 | * documents could be found here: | 37 | * documents could be found here: | |
38 | * | 38 | * | |
39 | * http://www.synopsys.com/dw/ipdir.php?ds=dwc_ether_mac10_100_1000_unive | 39 | * http://www.synopsys.com/dw/ipdir.php?ds=dwc_ether_mac10_100_1000_unive | |
40 | */ | 40 | */ | |
41 | 41 | |||
42 | #include <sys/cdefs.h> | 42 | #include <sys/cdefs.h> | |
43 | 43 | |||
44 | __KERNEL_RCSID(1, "$NetBSD: dwc_gmac.c,v 1.68 2019/10/19 06:40:20 tnn Exp $"); | 44 | __KERNEL_RCSID(1, "$NetBSD: dwc_gmac.c,v 1.69 2020/01/29 14:14:55 thorpej Exp $"); | |
45 | 45 | |||
46 | /* #define DWC_GMAC_DEBUG 1 */ | 46 | /* #define DWC_GMAC_DEBUG 1 */ | |
47 | 47 | |||
48 | #ifdef _KERNEL_OPT | 48 | #ifdef _KERNEL_OPT | |
49 | #include "opt_inet.h" | 49 | #include "opt_inet.h" | |
50 | #include "opt_net_mpsafe.h" | 50 | #include "opt_net_mpsafe.h" | |
51 | #endif | 51 | #endif | |
52 | 52 | |||
53 | #include <sys/param.h> | 53 | #include <sys/param.h> | |
54 | #include <sys/bus.h> | 54 | #include <sys/bus.h> | |
55 | #include <sys/device.h> | 55 | #include <sys/device.h> | |
56 | #include <sys/intr.h> | 56 | #include <sys/intr.h> | |
57 | #include <sys/systm.h> | 57 | #include <sys/systm.h> | |
58 | #include <sys/sockio.h> | 58 | #include <sys/sockio.h> | |
59 | #include <sys/cprng.h> | 59 | #include <sys/cprng.h> | |
60 | #include <sys/rndsource.h> | 60 | #include <sys/rndsource.h> | |
61 | 61 | |||
62 | #include <net/if.h> | 62 | #include <net/if.h> | |
63 | #include <net/if_ether.h> | 63 | #include <net/if_ether.h> | |
64 | #include <net/if_media.h> | 64 | #include <net/if_media.h> | |
65 | #include <net/bpf.h> | 65 | #include <net/bpf.h> | |
66 | #ifdef INET | 66 | #ifdef INET | |
67 | #include <netinet/if_inarp.h> | 67 | #include <netinet/if_inarp.h> | |
68 | #endif | 68 | #endif | |
69 | 69 | |||
70 | #include <dev/mii/miivar.h> | 70 | #include <dev/mii/miivar.h> | |
71 | 71 | |||
72 | #include <dev/ic/dwc_gmac_reg.h> | 72 | #include <dev/ic/dwc_gmac_reg.h> | |
73 | #include <dev/ic/dwc_gmac_var.h> | 73 | #include <dev/ic/dwc_gmac_var.h> | |
74 | 74 | |||
75 | static int dwc_gmac_miibus_read_reg(device_t, int, int, uint16_t *); | 75 | static int dwc_gmac_miibus_read_reg(device_t, int, int, uint16_t *); | |
76 | static int dwc_gmac_miibus_write_reg(device_t, int, int, uint16_t); | 76 | static int dwc_gmac_miibus_write_reg(device_t, int, int, uint16_t); | |
77 | static void dwc_gmac_miibus_statchg(struct ifnet *); | 77 | static void dwc_gmac_miibus_statchg(struct ifnet *); | |
78 | 78 | |||
79 | static int dwc_gmac_reset(struct dwc_gmac_softc *); | 79 | static int dwc_gmac_reset(struct dwc_gmac_softc *); | |
80 | static void dwc_gmac_write_hwaddr(struct dwc_gmac_softc *, uint8_t *); | 80 | static void dwc_gmac_write_hwaddr(struct dwc_gmac_softc *, uint8_t *); | |
81 | static int dwc_gmac_alloc_dma_rings(struct dwc_gmac_softc *); | 81 | static int dwc_gmac_alloc_dma_rings(struct dwc_gmac_softc *); | |
82 | static void dwc_gmac_free_dma_rings(struct dwc_gmac_softc *); | 82 | static void dwc_gmac_free_dma_rings(struct dwc_gmac_softc *); | |
83 | static int dwc_gmac_alloc_rx_ring(struct dwc_gmac_softc *, struct dwc_gmac_rx_ring *); | 83 | static int dwc_gmac_alloc_rx_ring(struct dwc_gmac_softc *, struct dwc_gmac_rx_ring *); | |
84 | static void dwc_gmac_reset_rx_ring(struct dwc_gmac_softc *, struct dwc_gmac_rx_ring *); | 84 | static void dwc_gmac_reset_rx_ring(struct dwc_gmac_softc *, struct dwc_gmac_rx_ring *); | |
85 | static void dwc_gmac_free_rx_ring(struct dwc_gmac_softc *, struct dwc_gmac_rx_ring *); | 85 | static void dwc_gmac_free_rx_ring(struct dwc_gmac_softc *, struct dwc_gmac_rx_ring *); | |
86 | static int dwc_gmac_alloc_tx_ring(struct dwc_gmac_softc *, struct dwc_gmac_tx_ring *); | 86 | static int dwc_gmac_alloc_tx_ring(struct dwc_gmac_softc *, struct dwc_gmac_tx_ring *); | |
87 | static void dwc_gmac_reset_tx_ring(struct dwc_gmac_softc *, struct dwc_gmac_tx_ring *); | 87 | static void dwc_gmac_reset_tx_ring(struct dwc_gmac_softc *, struct dwc_gmac_tx_ring *); | |
88 | static void dwc_gmac_free_tx_ring(struct dwc_gmac_softc *, struct dwc_gmac_tx_ring *); | 88 | static void dwc_gmac_free_tx_ring(struct dwc_gmac_softc *, struct dwc_gmac_tx_ring *); | |
89 | static void dwc_gmac_txdesc_sync(struct dwc_gmac_softc *, int, int, int); | 89 | static void dwc_gmac_txdesc_sync(struct dwc_gmac_softc *, int, int, int); | |
90 | static int dwc_gmac_init(struct ifnet *); | 90 | static int dwc_gmac_init(struct ifnet *); | |
91 | static int dwc_gmac_init_locked(struct ifnet *); | 91 | static int dwc_gmac_init_locked(struct ifnet *); | |
92 | static void dwc_gmac_stop(struct ifnet *, int); | 92 | static void dwc_gmac_stop(struct ifnet *, int); | |
93 | static void dwc_gmac_stop_locked(struct ifnet *, int); | 93 | static void dwc_gmac_stop_locked(struct ifnet *, int); | |
94 | static void dwc_gmac_start(struct ifnet *); | 94 | static void dwc_gmac_start(struct ifnet *); | |
95 | static void dwc_gmac_start_locked(struct ifnet *); | 95 | static void dwc_gmac_start_locked(struct ifnet *); | |
96 | static int dwc_gmac_queue(struct dwc_gmac_softc *, struct mbuf *); | 96 | static int dwc_gmac_queue(struct dwc_gmac_softc *, struct mbuf *); | |
97 | static int dwc_gmac_ioctl(struct ifnet *, u_long, void *); | 97 | static int dwc_gmac_ioctl(struct ifnet *, u_long, void *); | |
98 | static void dwc_gmac_tx_intr(struct dwc_gmac_softc *); | 98 | static void dwc_gmac_tx_intr(struct dwc_gmac_softc *); | |
99 | static void dwc_gmac_rx_intr(struct dwc_gmac_softc *); | 99 | static void dwc_gmac_rx_intr(struct dwc_gmac_softc *); | |
100 | static void dwc_gmac_setmulti(struct dwc_gmac_softc *); | 100 | static void dwc_gmac_setmulti(struct dwc_gmac_softc *); | |
101 | static int dwc_gmac_ifflags_cb(struct ethercom *); | 101 | static int dwc_gmac_ifflags_cb(struct ethercom *); | |
102 | static uint32_t bitrev32(uint32_t); | 102 | static uint32_t bitrev32(uint32_t); | |
103 | static void dwc_gmac_desc_set_owned_by_dev(struct dwc_gmac_dev_dmadesc *); | 103 | static void dwc_gmac_desc_set_owned_by_dev(struct dwc_gmac_dev_dmadesc *); | |
104 | static int dwc_gmac_desc_is_owned_by_dev(struct dwc_gmac_dev_dmadesc *); | 104 | static int dwc_gmac_desc_is_owned_by_dev(struct dwc_gmac_dev_dmadesc *); | |
105 | static void dwc_gmac_desc_std_set_len(struct dwc_gmac_dev_dmadesc *, int); | 105 | static void dwc_gmac_desc_std_set_len(struct dwc_gmac_dev_dmadesc *, int); | |
106 | static uint32_t dwc_gmac_desc_std_get_len(struct dwc_gmac_dev_dmadesc *); | 106 | static uint32_t dwc_gmac_desc_std_get_len(struct dwc_gmac_dev_dmadesc *); | |
107 | static void dwc_gmac_desc_std_tx_init_flags(struct dwc_gmac_dev_dmadesc *); | 107 | static void dwc_gmac_desc_std_tx_init_flags(struct dwc_gmac_dev_dmadesc *); | |
108 | static void dwc_gmac_desc_std_tx_set_first_frag(struct dwc_gmac_dev_dmadesc *); | 108 | static void dwc_gmac_desc_std_tx_set_first_frag(struct dwc_gmac_dev_dmadesc *); | |
109 | static void dwc_gmac_desc_std_tx_set_last_frag(struct dwc_gmac_dev_dmadesc *); | 109 | static void dwc_gmac_desc_std_tx_set_last_frag(struct dwc_gmac_dev_dmadesc *); | |
110 | static void dwc_gmac_desc_std_rx_init_flags(struct dwc_gmac_dev_dmadesc *); | 110 | static void dwc_gmac_desc_std_rx_init_flags(struct dwc_gmac_dev_dmadesc *); | |
111 | static int dwc_gmac_desc_std_rx_has_error(struct dwc_gmac_dev_dmadesc *); | 111 | static int dwc_gmac_desc_std_rx_has_error(struct dwc_gmac_dev_dmadesc *); | |
112 | static void dwc_gmac_desc_enh_set_len(struct dwc_gmac_dev_dmadesc *, int); | 112 | static void dwc_gmac_desc_enh_set_len(struct dwc_gmac_dev_dmadesc *, int); | |
113 | static uint32_t dwc_gmac_desc_enh_get_len(struct dwc_gmac_dev_dmadesc *); | 113 | static uint32_t dwc_gmac_desc_enh_get_len(struct dwc_gmac_dev_dmadesc *); | |
114 | static void dwc_gmac_desc_enh_tx_init_flags(struct dwc_gmac_dev_dmadesc *); | 114 | static void dwc_gmac_desc_enh_tx_init_flags(struct dwc_gmac_dev_dmadesc *); | |
115 | static void dwc_gmac_desc_enh_tx_set_first_frag(struct dwc_gmac_dev_dmadesc *); | 115 | static void dwc_gmac_desc_enh_tx_set_first_frag(struct dwc_gmac_dev_dmadesc *); | |
116 | static void dwc_gmac_desc_enh_tx_set_last_frag(struct dwc_gmac_dev_dmadesc *); | 116 | static void dwc_gmac_desc_enh_tx_set_last_frag(struct dwc_gmac_dev_dmadesc *); | |
117 | static void dwc_gmac_desc_enh_rx_init_flags(struct dwc_gmac_dev_dmadesc *); | 117 | static void dwc_gmac_desc_enh_rx_init_flags(struct dwc_gmac_dev_dmadesc *); | |
118 | static int dwc_gmac_desc_enh_rx_has_error(struct dwc_gmac_dev_dmadesc *); | 118 | static int dwc_gmac_desc_enh_rx_has_error(struct dwc_gmac_dev_dmadesc *); | |
119 | 119 | |||
120 | static const struct dwc_gmac_desc_methods desc_methods_standard = { | 120 | static const struct dwc_gmac_desc_methods desc_methods_standard = { | |
121 | .tx_init_flags = dwc_gmac_desc_std_tx_init_flags, | 121 | .tx_init_flags = dwc_gmac_desc_std_tx_init_flags, | |
122 | .tx_set_owned_by_dev = dwc_gmac_desc_set_owned_by_dev, | 122 | .tx_set_owned_by_dev = dwc_gmac_desc_set_owned_by_dev, | |
123 | .tx_is_owned_by_dev = dwc_gmac_desc_is_owned_by_dev, | 123 | .tx_is_owned_by_dev = dwc_gmac_desc_is_owned_by_dev, | |
124 | .tx_set_len = dwc_gmac_desc_std_set_len, | 124 | .tx_set_len = dwc_gmac_desc_std_set_len, | |
125 | .tx_set_first_frag = dwc_gmac_desc_std_tx_set_first_frag, | 125 | .tx_set_first_frag = dwc_gmac_desc_std_tx_set_first_frag, | |
126 | .tx_set_last_frag = dwc_gmac_desc_std_tx_set_last_frag, | 126 | .tx_set_last_frag = dwc_gmac_desc_std_tx_set_last_frag, | |
127 | .rx_init_flags = dwc_gmac_desc_std_rx_init_flags, | 127 | .rx_init_flags = dwc_gmac_desc_std_rx_init_flags, | |
128 | .rx_set_owned_by_dev = dwc_gmac_desc_set_owned_by_dev, | 128 | .rx_set_owned_by_dev = dwc_gmac_desc_set_owned_by_dev, | |
129 | .rx_is_owned_by_dev = dwc_gmac_desc_is_owned_by_dev, | 129 | .rx_is_owned_by_dev = dwc_gmac_desc_is_owned_by_dev, | |
130 | .rx_set_len = dwc_gmac_desc_std_set_len, | 130 | .rx_set_len = dwc_gmac_desc_std_set_len, | |
131 | .rx_get_len = dwc_gmac_desc_std_get_len, | 131 | .rx_get_len = dwc_gmac_desc_std_get_len, | |
132 | .rx_has_error = dwc_gmac_desc_std_rx_has_error | 132 | .rx_has_error = dwc_gmac_desc_std_rx_has_error | |
133 | }; | 133 | }; | |
134 | 134 | |||
135 | static const struct dwc_gmac_desc_methods desc_methods_enhanced = { | 135 | static const struct dwc_gmac_desc_methods desc_methods_enhanced = { | |
136 | .tx_init_flags = dwc_gmac_desc_enh_tx_init_flags, | 136 | .tx_init_flags = dwc_gmac_desc_enh_tx_init_flags, | |
137 | .tx_set_owned_by_dev = dwc_gmac_desc_set_owned_by_dev, | 137 | .tx_set_owned_by_dev = dwc_gmac_desc_set_owned_by_dev, | |
138 | .tx_is_owned_by_dev = dwc_gmac_desc_is_owned_by_dev, | 138 | .tx_is_owned_by_dev = dwc_gmac_desc_is_owned_by_dev, | |
139 | .tx_set_len = dwc_gmac_desc_enh_set_len, | 139 | .tx_set_len = dwc_gmac_desc_enh_set_len, | |
140 | .tx_set_first_frag = dwc_gmac_desc_enh_tx_set_first_frag, | 140 | .tx_set_first_frag = dwc_gmac_desc_enh_tx_set_first_frag, | |
141 | .tx_set_last_frag = dwc_gmac_desc_enh_tx_set_last_frag, | 141 | .tx_set_last_frag = dwc_gmac_desc_enh_tx_set_last_frag, | |
142 | .rx_init_flags = dwc_gmac_desc_enh_rx_init_flags, | 142 | .rx_init_flags = dwc_gmac_desc_enh_rx_init_flags, | |
143 | .rx_set_owned_by_dev = dwc_gmac_desc_set_owned_by_dev, | 143 | .rx_set_owned_by_dev = dwc_gmac_desc_set_owned_by_dev, | |
144 | .rx_is_owned_by_dev = dwc_gmac_desc_is_owned_by_dev, | 144 | .rx_is_owned_by_dev = dwc_gmac_desc_is_owned_by_dev, | |
145 | .rx_set_len = dwc_gmac_desc_enh_set_len, | 145 | .rx_set_len = dwc_gmac_desc_enh_set_len, | |
146 | .rx_get_len = dwc_gmac_desc_enh_get_len, | 146 | .rx_get_len = dwc_gmac_desc_enh_get_len, | |
147 | .rx_has_error = dwc_gmac_desc_enh_rx_has_error | 147 | .rx_has_error = dwc_gmac_desc_enh_rx_has_error | |
148 | }; | 148 | }; | |
149 | 149 | |||
150 | 150 | |||
151 | #define TX_DESC_OFFSET(N) ((AWGE_RX_RING_COUNT+(N)) \ | 151 | #define TX_DESC_OFFSET(N) ((AWGE_RX_RING_COUNT+(N)) \ | |
152 | *sizeof(struct dwc_gmac_dev_dmadesc)) | 152 | *sizeof(struct dwc_gmac_dev_dmadesc)) | |
153 | #define TX_NEXT(N) (((N)+1) & (AWGE_TX_RING_COUNT-1)) | 153 | #define TX_NEXT(N) (((N)+1) & (AWGE_TX_RING_COUNT-1)) | |
154 | 154 | |||
155 | #define RX_DESC_OFFSET(N) ((N)*sizeof(struct dwc_gmac_dev_dmadesc)) | 155 | #define RX_DESC_OFFSET(N) ((N)*sizeof(struct dwc_gmac_dev_dmadesc)) | |
156 | #define RX_NEXT(N) (((N)+1) & (AWGE_RX_RING_COUNT-1)) | 156 | #define RX_NEXT(N) (((N)+1) & (AWGE_RX_RING_COUNT-1)) | |
157 | 157 | |||
158 | 158 | |||
159 | 159 | |||
160 | #define GMAC_DEF_DMA_INT_MASK (GMAC_DMA_INT_TIE | GMAC_DMA_INT_RIE | \ | 160 | #define GMAC_DEF_DMA_INT_MASK (GMAC_DMA_INT_TIE | GMAC_DMA_INT_RIE | \ | |
161 | GMAC_DMA_INT_NIE | GMAC_DMA_INT_AIE | \ | 161 | GMAC_DMA_INT_NIE | GMAC_DMA_INT_AIE | \ | |
162 | GMAC_DMA_INT_FBE | GMAC_DMA_INT_UNE) | 162 | GMAC_DMA_INT_FBE | GMAC_DMA_INT_UNE) | |
163 | 163 | |||
164 | #define GMAC_DMA_INT_ERRORS (GMAC_DMA_INT_AIE | GMAC_DMA_INT_ERE | \ | 164 | #define GMAC_DMA_INT_ERRORS (GMAC_DMA_INT_AIE | GMAC_DMA_INT_ERE | \ | |
165 | GMAC_DMA_INT_FBE | \ | 165 | GMAC_DMA_INT_FBE | \ | |
166 | GMAC_DMA_INT_RWE | GMAC_DMA_INT_RUE | \ | 166 | GMAC_DMA_INT_RWE | GMAC_DMA_INT_RUE | \ | |
167 | GMAC_DMA_INT_UNE | GMAC_DMA_INT_OVE | \ | 167 | GMAC_DMA_INT_UNE | GMAC_DMA_INT_OVE | \ | |
168 | GMAC_DMA_INT_TJE) | 168 | GMAC_DMA_INT_TJE) | |
169 | 169 | |||
170 | #define AWIN_DEF_MAC_INTRMASK \ | 170 | #define AWIN_DEF_MAC_INTRMASK \ | |
171 | (AWIN_GMAC_MAC_INT_TSI | AWIN_GMAC_MAC_INT_ANEG | \ | 171 | (AWIN_GMAC_MAC_INT_TSI | AWIN_GMAC_MAC_INT_ANEG | \ | |
172 | AWIN_GMAC_MAC_INT_LINKCHG) | 172 | AWIN_GMAC_MAC_INT_LINKCHG) | |
173 | 173 | |||
174 | #ifdef DWC_GMAC_DEBUG | 174 | #ifdef DWC_GMAC_DEBUG | |
175 | static void dwc_gmac_dump_dma(struct dwc_gmac_softc *); | 175 | static void dwc_gmac_dump_dma(struct dwc_gmac_softc *); | |
176 | static void dwc_gmac_dump_tx_desc(struct dwc_gmac_softc *); | 176 | static void dwc_gmac_dump_tx_desc(struct dwc_gmac_softc *); | |
177 | static void dwc_gmac_dump_rx_desc(struct dwc_gmac_softc *); | 177 | static void dwc_gmac_dump_rx_desc(struct dwc_gmac_softc *); | |
178 | static void dwc_dump_and_abort(struct dwc_gmac_softc *, const char *); | 178 | static void dwc_dump_and_abort(struct dwc_gmac_softc *, const char *); | |
179 | static void dwc_dump_status(struct dwc_gmac_softc *); | 179 | static void dwc_dump_status(struct dwc_gmac_softc *); | |
180 | static void dwc_gmac_dump_ffilt(struct dwc_gmac_softc *, uint32_t); | 180 | static void dwc_gmac_dump_ffilt(struct dwc_gmac_softc *, uint32_t); | |
181 | #endif | 181 | #endif | |
182 | 182 | |||
183 | int | 183 | int | |
184 | dwc_gmac_attach(struct dwc_gmac_softc *sc, int phy_id, uint32_t mii_clk) | 184 | dwc_gmac_attach(struct dwc_gmac_softc *sc, int phy_id, uint32_t mii_clk) | |
185 | { | 185 | { | |
186 | uint8_t enaddr[ETHER_ADDR_LEN]; | 186 | uint8_t enaddr[ETHER_ADDR_LEN]; | |
187 | uint32_t maclo, machi, ver, hwft; | 187 | uint32_t maclo, machi, ver, hwft; | |
188 | struct mii_data * const mii = &sc->sc_mii; | 188 | struct mii_data * const mii = &sc->sc_mii; | |
189 | struct ifnet * const ifp = &sc->sc_ec.ec_if; | 189 | struct ifnet * const ifp = &sc->sc_ec.ec_if; | |
190 | prop_dictionary_t dict; | 190 | prop_dictionary_t dict; | |
191 | int rv; | 191 | int rv; | |
192 | 192 | |||
193 | mutex_init(&sc->sc_mdio_lock, MUTEX_DEFAULT, IPL_NET); | 193 | mutex_init(&sc->sc_mdio_lock, MUTEX_DEFAULT, IPL_NET); | |
194 | sc->sc_mii_clk = mii_clk & 7; | 194 | sc->sc_mii_clk = mii_clk & 7; | |
195 | 195 | |||
196 | dict = device_properties(sc->sc_dev); | 196 | dict = device_properties(sc->sc_dev); | |
197 | prop_data_t ea = dict ? prop_dictionary_get(dict, "mac-address") : NULL; | 197 | prop_data_t ea = dict ? prop_dictionary_get(dict, "mac-address") : NULL; | |
198 | if (ea != NULL) { | 198 | if (ea != NULL) { | |
199 | /* | 199 | /* | |
200 | * If the MAC address is overriden by a device property, | 200 | * If the MAC address is overriden by a device property, | |
201 | * use that. | 201 | * use that. | |
202 | */ | 202 | */ | |
203 | KASSERT(prop_object_type(ea) == PROP_TYPE_DATA); | 203 | KASSERT(prop_object_type(ea) == PROP_TYPE_DATA); | |
204 | KASSERT(prop_data_size(ea) == ETHER_ADDR_LEN); | 204 | KASSERT(prop_data_size(ea) == ETHER_ADDR_LEN); | |
205 | memcpy(enaddr, prop_data_data_nocopy(ea), ETHER_ADDR_LEN); | 205 | memcpy(enaddr, prop_data_data_nocopy(ea), ETHER_ADDR_LEN); | |
206 | } else { | 206 | } else { | |
207 | /* | 207 | /* | |
208 | * If we did not get an externaly configure address, | 208 | * If we did not get an externaly configure address, | |
209 | * try to read one from the current filter setup, | 209 | * try to read one from the current filter setup, | |
210 | * before resetting the chip. | 210 | * before resetting the chip. | |
211 | */ | 211 | */ | |
212 | maclo = bus_space_read_4(sc->sc_bst, sc->sc_bsh, | 212 | maclo = bus_space_read_4(sc->sc_bst, sc->sc_bsh, | |
213 | AWIN_GMAC_MAC_ADDR0LO); | 213 | AWIN_GMAC_MAC_ADDR0LO); | |
214 | machi = bus_space_read_4(sc->sc_bst, sc->sc_bsh, | 214 | machi = bus_space_read_4(sc->sc_bst, sc->sc_bsh, | |
215 | AWIN_GMAC_MAC_ADDR0HI); | 215 | AWIN_GMAC_MAC_ADDR0HI); | |
216 | 216 | |||
217 | if (maclo == 0xffffffff && (machi & 0xffff) == 0xffff) { | 217 | if (maclo == 0xffffffff && (machi & 0xffff) == 0xffff) { | |
218 | /* fake MAC address */ | 218 | /* fake MAC address */ | |
219 | maclo = 0x00f2 | (cprng_strong32() << 16); | 219 | maclo = 0x00f2 | (cprng_strong32() << 16); | |
220 | machi = cprng_strong32(); | 220 | machi = cprng_strong32(); | |
221 | } | 221 | } | |
222 | 222 | |||
223 | enaddr[0] = maclo & 0x0ff; | 223 | enaddr[0] = maclo & 0x0ff; | |
224 | enaddr[1] = (maclo >> 8) & 0x0ff; | 224 | enaddr[1] = (maclo >> 8) & 0x0ff; | |
225 | enaddr[2] = (maclo >> 16) & 0x0ff; | 225 | enaddr[2] = (maclo >> 16) & 0x0ff; | |
226 | enaddr[3] = (maclo >> 24) & 0x0ff; | 226 | enaddr[3] = (maclo >> 24) & 0x0ff; | |
227 | enaddr[4] = machi & 0x0ff; | 227 | enaddr[4] = machi & 0x0ff; | |
228 | enaddr[5] = (machi >> 8) & 0x0ff; | 228 | enaddr[5] = (machi >> 8) & 0x0ff; | |
229 | } | 229 | } | |
230 | 230 | |||
231 | ver = bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_VERSION); | 231 | ver = bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_VERSION); | |
232 | aprint_normal_dev(sc->sc_dev, "Core version: %08x\n", ver); | 232 | aprint_normal_dev(sc->sc_dev, "Core version: %08x\n", ver); | |
233 | 233 | |||
234 | /* | 234 | /* | |
235 | * Init chip and do initial setup | 235 | * Init chip and do initial setup | |
236 | */ | 236 | */ | |
237 | if (dwc_gmac_reset(sc) != 0) | 237 | if (dwc_gmac_reset(sc) != 0) | |
238 | return ENXIO; /* not much to cleanup, haven't attached yet */ | 238 | return ENXIO; /* not much to cleanup, haven't attached yet */ | |
239 | dwc_gmac_write_hwaddr(sc, enaddr); | 239 | dwc_gmac_write_hwaddr(sc, enaddr); | |
240 | aprint_normal_dev(sc->sc_dev, "Ethernet address %s\n", | 240 | aprint_normal_dev(sc->sc_dev, "Ethernet address %s\n", | |
241 | ether_sprintf(enaddr)); | 241 | ether_sprintf(enaddr)); | |
242 | 242 | |||
243 | hwft = 0; | 243 | hwft = 0; | |
244 | if (ver >= 0x35) { | 244 | if (ver >= 0x35) { | |
245 | hwft = bus_space_read_4(sc->sc_bst, sc->sc_bsh, | 245 | hwft = bus_space_read_4(sc->sc_bst, sc->sc_bsh, | |
246 | AWIN_GMAC_DMA_HWFEATURES); | 246 | AWIN_GMAC_DMA_HWFEATURES); | |
247 | aprint_normal_dev(sc->sc_dev, | 247 | aprint_normal_dev(sc->sc_dev, | |
248 | "HW feature mask: %x\n", hwft); | 248 | "HW feature mask: %x\n", hwft); | |
249 | } | 249 | } | |
250 | if (hwft & GMAC_DMA_FEAT_ENHANCED_DESC) { | 250 | if (hwft & GMAC_DMA_FEAT_ENHANCED_DESC) { | |
251 | aprint_normal_dev(sc->sc_dev, | 251 | aprint_normal_dev(sc->sc_dev, | |
252 | "Using enhanced descriptor format\n"); | 252 | "Using enhanced descriptor format\n"); | |
253 | sc->sc_descm = &desc_methods_enhanced; | 253 | sc->sc_descm = &desc_methods_enhanced; | |
254 | } else { | 254 | } else { | |
255 | sc->sc_descm = &desc_methods_standard; | 255 | sc->sc_descm = &desc_methods_standard; | |
256 | } | 256 | } | |
257 | 257 | |||
258 | /* | 258 | /* | |
259 | * Allocate Tx and Rx rings | 259 | * Allocate Tx and Rx rings | |
260 | */ | 260 | */ | |
261 | if (dwc_gmac_alloc_dma_rings(sc) != 0) { | 261 | if (dwc_gmac_alloc_dma_rings(sc) != 0) { | |
262 | aprint_error_dev(sc->sc_dev, "could not allocate DMA rings\n"); | 262 | aprint_error_dev(sc->sc_dev, "could not allocate DMA rings\n"); | |
263 | goto fail; | 263 | goto fail; | |
264 | } | 264 | } | |
265 | 265 | |||
266 | if (dwc_gmac_alloc_tx_ring(sc, &sc->sc_txq) != 0) { | 266 | if (dwc_gmac_alloc_tx_ring(sc, &sc->sc_txq) != 0) { | |
267 | aprint_error_dev(sc->sc_dev, "could not allocate Tx ring\n"); | 267 | aprint_error_dev(sc->sc_dev, "could not allocate Tx ring\n"); | |
268 | goto fail; | 268 | goto fail; | |
269 | } | 269 | } | |
270 | 270 | |||
271 | if (dwc_gmac_alloc_rx_ring(sc, &sc->sc_rxq) != 0) { | 271 | if (dwc_gmac_alloc_rx_ring(sc, &sc->sc_rxq) != 0) { | |
272 | aprint_error_dev(sc->sc_dev, "could not allocate Rx ring\n"); | 272 | aprint_error_dev(sc->sc_dev, "could not allocate Rx ring\n"); | |
273 | goto fail; | 273 | goto fail; | |
274 | } | 274 | } | |
275 | 275 | |||
276 | sc->sc_lock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_NET); | 276 | sc->sc_lock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_NET); | |
277 | mutex_init(&sc->sc_txq.t_mtx, MUTEX_DEFAULT, IPL_NET); | 277 | mutex_init(&sc->sc_txq.t_mtx, MUTEX_DEFAULT, IPL_NET); | |
278 | mutex_init(&sc->sc_rxq.r_mtx, MUTEX_DEFAULT, IPL_NET); | 278 | mutex_init(&sc->sc_rxq.r_mtx, MUTEX_DEFAULT, IPL_NET); | |
279 | 279 | |||
280 | /* | 280 | /* | |
281 | * Prepare interface data | 281 | * Prepare interface data | |
282 | */ | 282 | */ | |
283 | ifp->if_softc = sc; | 283 | ifp->if_softc = sc; | |
284 | strlcpy(ifp->if_xname, device_xname(sc->sc_dev), IFNAMSIZ); | 284 | strlcpy(ifp->if_xname, device_xname(sc->sc_dev), IFNAMSIZ); | |
285 | ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; | 285 | ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; | |
286 | #ifdef DWCGMAC_MPSAFE | 286 | #ifdef DWCGMAC_MPSAFE | |
287 | ifp->if_extflags = IFEF_MPSAFE; | 287 | ifp->if_extflags = IFEF_MPSAFE; | |
288 | #endif | 288 | #endif | |
289 | ifp->if_ioctl = dwc_gmac_ioctl; | 289 | ifp->if_ioctl = dwc_gmac_ioctl; | |
290 | ifp->if_start = dwc_gmac_start; | 290 | ifp->if_start = dwc_gmac_start; | |
291 | ifp->if_init = dwc_gmac_init; | 291 | ifp->if_init = dwc_gmac_init; | |
292 | ifp->if_stop = dwc_gmac_stop; | 292 | ifp->if_stop = dwc_gmac_stop; | |
293 | IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN); | 293 | IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN); | |
294 | IFQ_SET_READY(&ifp->if_snd); | 294 | IFQ_SET_READY(&ifp->if_snd); | |
295 | 295 | |||
296 | /* | 296 | /* | |
297 | * Attach MII subdevices | 297 | * Attach MII subdevices | |
298 | */ | 298 | */ | |
299 | sc->sc_ec.ec_mii = &sc->sc_mii; | 299 | sc->sc_ec.ec_mii = &sc->sc_mii; | |
300 | ifmedia_init(&mii->mii_media, 0, ether_mediachange, ether_mediastatus); | 300 | ifmedia_init(&mii->mii_media, 0, ether_mediachange, ether_mediastatus); | |
301 | mii->mii_ifp = ifp; | 301 | mii->mii_ifp = ifp; | |
302 | mii->mii_readreg = dwc_gmac_miibus_read_reg; | 302 | mii->mii_readreg = dwc_gmac_miibus_read_reg; | |
303 | mii->mii_writereg = dwc_gmac_miibus_write_reg; | 303 | mii->mii_writereg = dwc_gmac_miibus_write_reg; | |
304 | mii->mii_statchg = dwc_gmac_miibus_statchg; | 304 | mii->mii_statchg = dwc_gmac_miibus_statchg; | |
305 | mii_attach(sc->sc_dev, mii, 0xffffffff, phy_id, MII_OFFSET_ANY, | 305 | mii_attach(sc->sc_dev, mii, 0xffffffff, phy_id, MII_OFFSET_ANY, | |
306 | MIIF_DOPAUSE); | 306 | MIIF_DOPAUSE); | |
307 | 307 | |||
308 | if (LIST_EMPTY(&mii->mii_phys)) { | 308 | if (LIST_EMPTY(&mii->mii_phys)) { | |
309 | aprint_error_dev(sc->sc_dev, "no PHY found!\n"); | 309 | aprint_error_dev(sc->sc_dev, "no PHY found!\n"); | |
310 | ifmedia_add(&mii->mii_media, IFM_ETHER | IFM_MANUAL, 0, NULL); | 310 | ifmedia_add(&mii->mii_media, IFM_ETHER | IFM_MANUAL, 0, NULL); | |
311 | ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_MANUAL); | 311 | ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_MANUAL); | |
312 | } else { | 312 | } else { | |
313 | ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_AUTO); | 313 | ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_AUTO); | |
314 | } | 314 | } | |
315 | 315 | |||
316 | /* | 316 | /* | |
317 | * We can support 802.1Q VLAN-sized frames. | 317 | * We can support 802.1Q VLAN-sized frames. | |
318 | */ | 318 | */ | |
319 | sc->sc_ec.ec_capabilities |= ETHERCAP_VLAN_MTU; | 319 | sc->sc_ec.ec_capabilities |= ETHERCAP_VLAN_MTU; | |
320 | 320 | |||
321 | /* | 321 | /* | |
322 | * Ready, attach interface | 322 | * Ready, attach interface | |
323 | */ | 323 | */ | |
324 | /* Attach the interface. */ | 324 | /* Attach the interface. */ | |
325 | rv = if_initialize(ifp); | 325 | rv = if_initialize(ifp); | |
326 | if (rv != 0) | 326 | if (rv != 0) | |
327 | goto fail_2; | 327 | goto fail_2; | |
328 | sc->sc_ipq = if_percpuq_create(&sc->sc_ec.ec_if); | 328 | sc->sc_ipq = if_percpuq_create(&sc->sc_ec.ec_if); | |
329 | if_deferred_start_init(ifp, NULL); | 329 | if_deferred_start_init(ifp, NULL); | |
330 | ether_ifattach(ifp, enaddr); | 330 | ether_ifattach(ifp, enaddr); | |
331 | ether_set_ifflags_cb(&sc->sc_ec, dwc_gmac_ifflags_cb); | 331 | ether_set_ifflags_cb(&sc->sc_ec, dwc_gmac_ifflags_cb); | |
332 | if_register(ifp); | 332 | if_register(ifp); | |
333 | rnd_attach_source(&sc->rnd_source, device_xname(sc->sc_dev), | 333 | rnd_attach_source(&sc->rnd_source, device_xname(sc->sc_dev), | |
334 | RND_TYPE_NET, RND_FLAG_DEFAULT); | 334 | RND_TYPE_NET, RND_FLAG_DEFAULT); | |
335 | 335 | |||
336 | /* | 336 | /* | |
337 | * Enable interrupts | 337 | * Enable interrupts | |
338 | */ | 338 | */ | |
339 | mutex_enter(sc->sc_lock); | 339 | mutex_enter(sc->sc_lock); | |
340 | bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_INTMASK, | 340 | bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_INTMASK, | |
341 | AWIN_DEF_MAC_INTRMASK); | 341 | AWIN_DEF_MAC_INTRMASK); | |
342 | bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_INTENABLE, | 342 | bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_INTENABLE, | |
343 | GMAC_DEF_DMA_INT_MASK); | 343 | GMAC_DEF_DMA_INT_MASK); | |
344 | mutex_exit(sc->sc_lock); | 344 | mutex_exit(sc->sc_lock); | |
345 | 345 | |||
346 | return 0; | 346 | return 0; | |
347 | 347 | |||
348 | fail_2: | 348 | fail_2: | |
349 | ifmedia_removeall(&mii->mii_media); | 349 | ifmedia_removeall(&mii->mii_media); | |
350 | mii_detach(mii, MII_PHY_ANY, MII_OFFSET_ANY); | 350 | mii_detach(mii, MII_PHY_ANY, MII_OFFSET_ANY); | |
351 | mutex_destroy(&sc->sc_txq.t_mtx); | 351 | mutex_destroy(&sc->sc_txq.t_mtx); | |
352 | mutex_destroy(&sc->sc_rxq.r_mtx); | 352 | mutex_destroy(&sc->sc_rxq.r_mtx); | |
353 | mutex_obj_free(sc->sc_lock); | 353 | mutex_obj_free(sc->sc_lock); | |
354 | fail: | 354 | fail: | |
355 | dwc_gmac_free_rx_ring(sc, &sc->sc_rxq); | 355 | dwc_gmac_free_rx_ring(sc, &sc->sc_rxq); | |
356 | dwc_gmac_free_tx_ring(sc, &sc->sc_txq); | 356 | dwc_gmac_free_tx_ring(sc, &sc->sc_txq); | |
357 | dwc_gmac_free_dma_rings(sc); | 357 | dwc_gmac_free_dma_rings(sc); | |
358 | mutex_destroy(&sc->sc_mdio_lock); | 358 | mutex_destroy(&sc->sc_mdio_lock); | |
359 | 359 | |||
360 | return ENXIO; | 360 | return ENXIO; | |
361 | } | 361 | } | |
362 | 362 | |||
363 | 363 | |||
364 | 364 | |||
365 | static int | 365 | static int | |
366 | dwc_gmac_reset(struct dwc_gmac_softc *sc) | 366 | dwc_gmac_reset(struct dwc_gmac_softc *sc) | |
367 | { | 367 | { | |
368 | size_t cnt; | 368 | size_t cnt; | |
369 | bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_BUSMODE, | 369 | bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_BUSMODE, | |
370 | bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_BUSMODE) | 370 | bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_BUSMODE) | |
371 | | GMAC_BUSMODE_RESET); | 371 | | GMAC_BUSMODE_RESET); | |
372 | for (cnt = 0; cnt < 3000; cnt++) { | 372 | for (cnt = 0; cnt < 3000; cnt++) { | |
373 | if ((bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_BUSMODE) | 373 | if ((bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_BUSMODE) | |
374 | & GMAC_BUSMODE_RESET) == 0) | 374 | & GMAC_BUSMODE_RESET) == 0) | |
375 | return 0; | 375 | return 0; | |
376 | delay(10); | 376 | delay(10); | |
377 | } | 377 | } | |
378 | 378 | |||
379 | aprint_error_dev(sc->sc_dev, "reset timed out\n"); | 379 | aprint_error_dev(sc->sc_dev, "reset timed out\n"); | |
380 | return EIO; | 380 | return EIO; | |
381 | } | 381 | } | |
382 | 382 | |||
383 | static void | 383 | static void | |
384 | dwc_gmac_write_hwaddr(struct dwc_gmac_softc *sc, | 384 | dwc_gmac_write_hwaddr(struct dwc_gmac_softc *sc, | |
385 | uint8_t enaddr[ETHER_ADDR_LEN]) | 385 | uint8_t enaddr[ETHER_ADDR_LEN]) | |
386 | { | 386 | { | |
387 | uint32_t hi, lo; | 387 | uint32_t hi, lo; | |
388 | 388 | |||
389 | hi = enaddr[4] | (enaddr[5] << 8); | 389 | hi = enaddr[4] | (enaddr[5] << 8); | |
390 | lo = enaddr[0] | (enaddr[1] << 8) | (enaddr[2] << 16) | 390 | lo = enaddr[0] | (enaddr[1] << 8) | (enaddr[2] << 16) | |
391 | | (enaddr[3] << 24); | 391 | | (enaddr[3] << 24); | |
392 | bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_ADDR0HI, hi); | 392 | bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_ADDR0HI, hi); | |
393 | bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_ADDR0LO, lo); | 393 | bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_ADDR0LO, lo); | |
394 | } | 394 | } | |
395 | 395 | |||
396 | static int | 396 | static int | |
397 | dwc_gmac_miibus_read_reg(device_t self, int phy, int reg, uint16_t *val) | 397 | dwc_gmac_miibus_read_reg(device_t self, int phy, int reg, uint16_t *val) | |
398 | { | 398 | { | |
399 | struct dwc_gmac_softc * const sc = device_private(self); | 399 | struct dwc_gmac_softc * const sc = device_private(self); | |
400 | uint16_t mii; | 400 | uint16_t mii; | |
401 | size_t cnt; | 401 | size_t cnt; | |
402 | 402 | |||
403 | mii = __SHIFTIN(phy, GMAC_MII_PHY_MASK) | 403 | mii = __SHIFTIN(phy, GMAC_MII_PHY_MASK) | |
404 | | __SHIFTIN(reg, GMAC_MII_REG_MASK) | 404 | | __SHIFTIN(reg, GMAC_MII_REG_MASK) | |
405 | | __SHIFTIN(sc->sc_mii_clk, GMAC_MII_CLKMASK) | 405 | | __SHIFTIN(sc->sc_mii_clk, GMAC_MII_CLKMASK) | |
406 | | GMAC_MII_BUSY; | 406 | | GMAC_MII_BUSY; | |
407 | 407 | |||
408 | mutex_enter(&sc->sc_mdio_lock); | 408 | mutex_enter(&sc->sc_mdio_lock); | |
409 | bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_MIIADDR, mii); | 409 | bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_MIIADDR, mii); | |
410 | 410 | |||
411 | for (cnt = 0; cnt < 1000; cnt++) { | 411 | for (cnt = 0; cnt < 1000; cnt++) { | |
412 | if (!(bus_space_read_4(sc->sc_bst, sc->sc_bsh, | 412 | if (!(bus_space_read_4(sc->sc_bst, sc->sc_bsh, | |
413 | AWIN_GMAC_MAC_MIIADDR) & GMAC_MII_BUSY)) { | 413 | AWIN_GMAC_MAC_MIIADDR) & GMAC_MII_BUSY)) { | |
414 | *val = bus_space_read_4(sc->sc_bst, sc->sc_bsh, | 414 | *val = bus_space_read_4(sc->sc_bst, sc->sc_bsh, | |
415 | AWIN_GMAC_MAC_MIIDATA); | 415 | AWIN_GMAC_MAC_MIIDATA); | |
416 | break; | 416 | break; | |
417 | } | 417 | } | |
418 | delay(10); | 418 | delay(10); | |
419 | } | 419 | } | |
420 | 420 | |||
421 | mutex_exit(&sc->sc_mdio_lock); | 421 | mutex_exit(&sc->sc_mdio_lock); | |
422 | 422 | |||
423 | if (cnt >= 1000) | 423 | if (cnt >= 1000) | |
424 | return ETIMEDOUT; | 424 | return ETIMEDOUT; | |
425 | 425 | |||
426 | return 0; | 426 | return 0; | |
427 | } | 427 | } | |
428 | 428 | |||
429 | static int | 429 | static int | |
430 | dwc_gmac_miibus_write_reg(device_t self, int phy, int reg, uint16_t val) | 430 | dwc_gmac_miibus_write_reg(device_t self, int phy, int reg, uint16_t val) | |
431 | { | 431 | { | |
432 | struct dwc_gmac_softc * const sc = device_private(self); | 432 | struct dwc_gmac_softc * const sc = device_private(self); | |
433 | uint16_t mii; | 433 | uint16_t mii; | |
434 | size_t cnt; | 434 | size_t cnt; | |
435 | 435 | |||
436 | mii = __SHIFTIN(phy, GMAC_MII_PHY_MASK) | 436 | mii = __SHIFTIN(phy, GMAC_MII_PHY_MASK) | |
437 | | __SHIFTIN(reg, GMAC_MII_REG_MASK) | 437 | | __SHIFTIN(reg, GMAC_MII_REG_MASK) | |
438 | | __SHIFTIN(sc->sc_mii_clk, GMAC_MII_CLKMASK) | 438 | | __SHIFTIN(sc->sc_mii_clk, GMAC_MII_CLKMASK) | |
439 | | GMAC_MII_BUSY | GMAC_MII_WRITE; | 439 | | GMAC_MII_BUSY | GMAC_MII_WRITE; | |
440 | 440 | |||
441 | mutex_enter(&sc->sc_mdio_lock); | 441 | mutex_enter(&sc->sc_mdio_lock); | |
442 | bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_MIIDATA, val); | 442 | bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_MIIDATA, val); | |
443 | bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_MIIADDR, mii); | 443 | bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_MIIADDR, mii); | |
444 | 444 | |||
445 | for (cnt = 0; cnt < 1000; cnt++) { | 445 | for (cnt = 0; cnt < 1000; cnt++) { | |
446 | if (!(bus_space_read_4(sc->sc_bst, sc->sc_bsh, | 446 | if (!(bus_space_read_4(sc->sc_bst, sc->sc_bsh, | |
447 | AWIN_GMAC_MAC_MIIADDR) & GMAC_MII_BUSY)) | 447 | AWIN_GMAC_MAC_MIIADDR) & GMAC_MII_BUSY)) | |
448 | break; | 448 | break; | |
449 | delay(10); | 449 | delay(10); | |
450 | } | 450 | } | |
451 | 451 | |||
452 | mutex_exit(&sc->sc_mdio_lock); | 452 | mutex_exit(&sc->sc_mdio_lock); | |
453 | 453 | |||
454 | if (cnt >= 1000) | 454 | if (cnt >= 1000) | |
455 | return ETIMEDOUT; | 455 | return ETIMEDOUT; | |
456 | 456 | |||
457 | return 0; | 457 | return 0; | |
458 | } | 458 | } | |
459 | 459 | |||
460 | static int | 460 | static int | |
461 | dwc_gmac_alloc_rx_ring(struct dwc_gmac_softc *sc, | 461 | dwc_gmac_alloc_rx_ring(struct dwc_gmac_softc *sc, | |
462 | struct dwc_gmac_rx_ring *ring) | 462 | struct dwc_gmac_rx_ring *ring) | |
463 | { | 463 | { | |
464 | struct dwc_gmac_rx_data *data; | 464 | struct dwc_gmac_rx_data *data; | |
465 | bus_addr_t physaddr; | 465 | bus_addr_t physaddr; | |
466 | const size_t descsize = AWGE_RX_RING_COUNT * sizeof(*ring->r_desc); | 466 | const size_t descsize = AWGE_RX_RING_COUNT * sizeof(*ring->r_desc); | |
467 | int error, i, next; | 467 | int error, i, next; | |
468 | 468 | |||
469 | ring->r_cur = ring->r_next = 0; | 469 | ring->r_cur = ring->r_next = 0; | |
470 | memset(ring->r_desc, 0, descsize); | 470 | memset(ring->r_desc, 0, descsize); | |
471 | 471 | |||
472 | /* | 472 | /* | |
473 | * Pre-allocate Rx buffers and populate Rx ring. | 473 | * Pre-allocate Rx buffers and populate Rx ring. | |
474 | */ | 474 | */ | |
475 | for (i = 0; i < AWGE_RX_RING_COUNT; i++) { | 475 | for (i = 0; i < AWGE_RX_RING_COUNT; i++) { | |
476 | struct dwc_gmac_dev_dmadesc *desc; | 476 | struct dwc_gmac_dev_dmadesc *desc; | |
477 | 477 | |||
478 | data = &sc->sc_rxq.r_data[i]; | 478 | data = &sc->sc_rxq.r_data[i]; | |
479 | 479 | |||
480 | MGETHDR(data->rd_m, M_DONTWAIT, MT_DATA); | 480 | MGETHDR(data->rd_m, M_DONTWAIT, MT_DATA); | |
481 | if (data->rd_m == NULL) { | 481 | if (data->rd_m == NULL) { | |
482 | aprint_error_dev(sc->sc_dev, | 482 | aprint_error_dev(sc->sc_dev, | |
483 | "could not allocate rx mbuf #%d\n", i); | 483 | "could not allocate rx mbuf #%d\n", i); | |
484 | error = ENOMEM; | 484 | error = ENOMEM; | |
485 | goto fail; | 485 | goto fail; | |
486 | } | 486 | } | |
487 | error = bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1, | 487 | error = bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1, | |
488 | MCLBYTES, 0, BUS_DMA_NOWAIT, &data->rd_map); | 488 | MCLBYTES, 0, BUS_DMA_NOWAIT, &data->rd_map); | |
489 | if (error != 0) { | 489 | if (error != 0) { | |
490 | aprint_error_dev(sc->sc_dev, | 490 | aprint_error_dev(sc->sc_dev, | |
491 | "could not create DMA map\n"); | 491 | "could not create DMA map\n"); | |
492 | data->rd_map = NULL; | 492 | data->rd_map = NULL; | |
493 | goto fail; | 493 | goto fail; | |
494 | } | 494 | } | |
495 | MCLGET(data->rd_m, M_DONTWAIT); | 495 | MCLGET(data->rd_m, M_DONTWAIT); | |
496 | if (!(data->rd_m->m_flags & M_EXT)) { | 496 | if (!(data->rd_m->m_flags & M_EXT)) { | |
497 | aprint_error_dev(sc->sc_dev, | 497 | aprint_error_dev(sc->sc_dev, | |
498 | "could not allocate mbuf cluster #%d\n", i); | 498 | "could not allocate mbuf cluster #%d\n", i); | |
499 | error = ENOMEM; | 499 | error = ENOMEM; | |
500 | goto fail; | 500 | goto fail; | |
501 | } | 501 | } | |
502 | data->rd_m->m_len = data->rd_m->m_pkthdr.len | 502 | data->rd_m->m_len = data->rd_m->m_pkthdr.len | |
503 | = data->rd_m->m_ext.ext_size; | 503 | = data->rd_m->m_ext.ext_size; | |
504 | if (data->rd_m->m_len > AWGE_MAX_PACKET) { | 504 | if (data->rd_m->m_len > AWGE_MAX_PACKET) { | |
505 | data->rd_m->m_len = data->rd_m->m_pkthdr.len | 505 | data->rd_m->m_len = data->rd_m->m_pkthdr.len | |
506 | = AWGE_MAX_PACKET; | 506 | = AWGE_MAX_PACKET; | |
507 | } | 507 | } | |
508 | 508 | |||
509 | error = bus_dmamap_load_mbuf(sc->sc_dmat, data->rd_map, | 509 | error = bus_dmamap_load_mbuf(sc->sc_dmat, data->rd_map, | |
510 | data->rd_m, BUS_DMA_READ | BUS_DMA_NOWAIT); | 510 | data->rd_m, BUS_DMA_READ | BUS_DMA_NOWAIT); | |
511 | if (error != 0) { | 511 | if (error != 0) { | |
512 | aprint_error_dev(sc->sc_dev, | 512 | aprint_error_dev(sc->sc_dev, | |
513 | "could not load rx buf DMA map #%d", i); | 513 | "could not load rx buf DMA map #%d", i); | |
514 | goto fail; | 514 | goto fail; | |
515 | } | 515 | } | |
516 | bus_dmamap_sync(sc->sc_dmat, data->rd_map, 0, | 516 | bus_dmamap_sync(sc->sc_dmat, data->rd_map, 0, | |
517 | data->rd_map->dm_mapsize, BUS_DMASYNC_PREREAD); | 517 | data->rd_map->dm_mapsize, BUS_DMASYNC_PREREAD); | |
518 | physaddr = data->rd_map->dm_segs[0].ds_addr; | 518 | physaddr = data->rd_map->dm_segs[0].ds_addr; | |
519 | 519 | |||
520 | desc = &sc->sc_rxq.r_desc[i]; | 520 | desc = &sc->sc_rxq.r_desc[i]; | |
521 | desc->ddesc_data = htole32(physaddr); | 521 | desc->ddesc_data = htole32(physaddr); | |
522 | next = RX_NEXT(i); | 522 | next = RX_NEXT(i); | |
523 | desc->ddesc_next = htole32(ring->r_physaddr | 523 | desc->ddesc_next = htole32(ring->r_physaddr | |
524 | + next * sizeof(*desc)); | 524 | + next * sizeof(*desc)); | |
525 | sc->sc_descm->rx_init_flags(desc); | 525 | sc->sc_descm->rx_init_flags(desc); | |
526 | sc->sc_descm->rx_set_len(desc, data->rd_m->m_len); | 526 | sc->sc_descm->rx_set_len(desc, data->rd_m->m_len); | |
527 | sc->sc_descm->rx_set_owned_by_dev(desc); | 527 | sc->sc_descm->rx_set_owned_by_dev(desc); | |
528 | } | 528 | } | |
529 | 529 | |||
530 | bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_ring_map, 0, | 530 | bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_ring_map, 0, | |
531 | AWGE_RX_RING_COUNT*sizeof(struct dwc_gmac_dev_dmadesc), | 531 | AWGE_RX_RING_COUNT*sizeof(struct dwc_gmac_dev_dmadesc), | |
532 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | 532 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); | |
533 | bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_RX_ADDR, | 533 | bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_RX_ADDR, | |
534 | ring->r_physaddr); | 534 | ring->r_physaddr); | |
535 | 535 | |||
536 | return 0; | 536 | return 0; | |
537 | 537 | |||
538 | fail: | 538 | fail: | |
539 | dwc_gmac_free_rx_ring(sc, ring); | 539 | dwc_gmac_free_rx_ring(sc, ring); | |
540 | return error; | 540 | return error; | |
541 | } | 541 | } | |
542 | 542 | |||
543 | static void | 543 | static void | |
544 | dwc_gmac_reset_rx_ring(struct dwc_gmac_softc *sc, | 544 | dwc_gmac_reset_rx_ring(struct dwc_gmac_softc *sc, | |
545 | struct dwc_gmac_rx_ring *ring) | 545 | struct dwc_gmac_rx_ring *ring) | |
546 | { | 546 | { | |
547 | struct dwc_gmac_dev_dmadesc *desc; | 547 | struct dwc_gmac_dev_dmadesc *desc; | |
548 | struct dwc_gmac_rx_data *data; | 548 | struct dwc_gmac_rx_data *data; | |
549 | int i; | 549 | int i; | |
550 | 550 | |||
551 | mutex_enter(&ring->r_mtx); | 551 | mutex_enter(&ring->r_mtx); | |
552 | for (i = 0; i < AWGE_RX_RING_COUNT; i++) { | 552 | for (i = 0; i < AWGE_RX_RING_COUNT; i++) { | |
553 | desc = &sc->sc_rxq.r_desc[i]; | 553 | desc = &sc->sc_rxq.r_desc[i]; | |
554 | data = &sc->sc_rxq.r_data[i]; | 554 | data = &sc->sc_rxq.r_data[i]; | |
555 | sc->sc_descm->rx_init_flags(desc); | 555 | sc->sc_descm->rx_init_flags(desc); | |
556 | sc->sc_descm->rx_set_len(desc, data->rd_m->m_len); | 556 | sc->sc_descm->rx_set_len(desc, data->rd_m->m_len); | |
557 | sc->sc_descm->rx_set_owned_by_dev(desc); | 557 | sc->sc_descm->rx_set_owned_by_dev(desc); | |
558 | } | 558 | } | |
559 | 559 | |||
560 | bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_ring_map, 0, | 560 | bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_ring_map, 0, | |
561 | AWGE_RX_RING_COUNT*sizeof(struct dwc_gmac_dev_dmadesc), | 561 | AWGE_RX_RING_COUNT*sizeof(struct dwc_gmac_dev_dmadesc), | |
562 | BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); | 562 | BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); | |
563 | 563 | |||
564 | ring->r_cur = ring->r_next = 0; | 564 | ring->r_cur = ring->r_next = 0; | |
565 | /* reset DMA address to start of ring */ | 565 | /* reset DMA address to start of ring */ | |
566 | bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_RX_ADDR, | 566 | bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_RX_ADDR, | |
567 | sc->sc_rxq.r_physaddr); | 567 | sc->sc_rxq.r_physaddr); | |
568 | mutex_exit(&ring->r_mtx); | 568 | mutex_exit(&ring->r_mtx); | |
569 | } | 569 | } | |
570 | 570 | |||
571 | static int | 571 | static int | |
572 | dwc_gmac_alloc_dma_rings(struct dwc_gmac_softc *sc) | 572 | dwc_gmac_alloc_dma_rings(struct dwc_gmac_softc *sc) | |
573 | { | 573 | { | |
574 | const size_t descsize = AWGE_TOTAL_RING_COUNT * | 574 | const size_t descsize = AWGE_TOTAL_RING_COUNT * | |
575 | sizeof(struct dwc_gmac_dev_dmadesc); | 575 | sizeof(struct dwc_gmac_dev_dmadesc); | |
576 | int error, nsegs; | 576 | int error, nsegs; | |
577 | void *rings; | 577 | void *rings; | |
578 | 578 | |||
579 | error = bus_dmamap_create(sc->sc_dmat, descsize, 1, descsize, 0, | 579 | error = bus_dmamap_create(sc->sc_dmat, descsize, 1, descsize, 0, | |
580 | BUS_DMA_NOWAIT, &sc->sc_dma_ring_map); | 580 | BUS_DMA_NOWAIT, &sc->sc_dma_ring_map); | |
581 | if (error != 0) { | 581 | if (error != 0) { | |
582 | aprint_error_dev(sc->sc_dev, | 582 | aprint_error_dev(sc->sc_dev, | |
583 | "could not create desc DMA map\n"); | 583 | "could not create desc DMA map\n"); | |
584 | sc->sc_dma_ring_map = NULL; | 584 | sc->sc_dma_ring_map = NULL; | |
585 | goto fail; | 585 | goto fail; | |
586 | } | 586 | } | |
587 | 587 | |||
588 | error = bus_dmamem_alloc(sc->sc_dmat, descsize, PAGE_SIZE, 0, | 588 | error = bus_dmamem_alloc(sc->sc_dmat, descsize, PAGE_SIZE, 0, | |
589 | &sc->sc_dma_ring_seg, 1, &nsegs, BUS_DMA_NOWAIT |BUS_DMA_COHERENT); | 589 | &sc->sc_dma_ring_seg, 1, &nsegs, BUS_DMA_NOWAIT |BUS_DMA_COHERENT); | |
590 | if (error != 0) { | 590 | if (error != 0) { | |
591 | aprint_error_dev(sc->sc_dev, | 591 | aprint_error_dev(sc->sc_dev, | |
592 | "could not map DMA memory\n"); | 592 | "could not map DMA memory\n"); | |
593 | goto fail; | 593 | goto fail; | |
594 | } | 594 | } | |
595 | 595 | |||
596 | error = bus_dmamem_map(sc->sc_dmat, &sc->sc_dma_ring_seg, nsegs, | 596 | error = bus_dmamem_map(sc->sc_dmat, &sc->sc_dma_ring_seg, nsegs, | |
597 | descsize, &rings, BUS_DMA_NOWAIT | BUS_DMA_COHERENT); | 597 | descsize, &rings, BUS_DMA_NOWAIT | BUS_DMA_COHERENT); | |
598 | if (error != 0) { | 598 | if (error != 0) { | |
599 | aprint_error_dev(sc->sc_dev, | 599 | aprint_error_dev(sc->sc_dev, | |
600 | "could not allocate DMA memory\n"); | 600 | "could not allocate DMA memory\n"); | |
601 | goto fail; | 601 | goto fail; | |
602 | } | 602 | } | |
603 | 603 | |||
604 | error = bus_dmamap_load(sc->sc_dmat, sc->sc_dma_ring_map, rings, | 604 | error = bus_dmamap_load(sc->sc_dmat, sc->sc_dma_ring_map, rings, | |
605 | descsize, NULL, BUS_DMA_NOWAIT | BUS_DMA_COHERENT); | 605 | descsize, NULL, BUS_DMA_NOWAIT | BUS_DMA_COHERENT); | |
606 | if (error != 0) { | 606 | if (error != 0) { | |
607 | aprint_error_dev(sc->sc_dev, | 607 | aprint_error_dev(sc->sc_dev, | |
608 | "could not load desc DMA map\n"); | 608 | "could not load desc DMA map\n"); | |
609 | goto fail; | 609 | goto fail; | |
610 | } | 610 | } | |
611 | 611 | |||
612 | /* give first AWGE_RX_RING_COUNT to the RX side */ | 612 | /* give first AWGE_RX_RING_COUNT to the RX side */ | |
613 | sc->sc_rxq.r_desc = rings; | 613 | sc->sc_rxq.r_desc = rings; | |
614 | sc->sc_rxq.r_physaddr = sc->sc_dma_ring_map->dm_segs[0].ds_addr; | 614 | sc->sc_rxq.r_physaddr = sc->sc_dma_ring_map->dm_segs[0].ds_addr; | |
615 | 615 | |||
616 | /* and next rings to the TX side */ | 616 | /* and next rings to the TX side */ | |
617 | sc->sc_txq.t_desc = sc->sc_rxq.r_desc + AWGE_RX_RING_COUNT; | 617 | sc->sc_txq.t_desc = sc->sc_rxq.r_desc + AWGE_RX_RING_COUNT; | |
618 | sc->sc_txq.t_physaddr = sc->sc_rxq.r_physaddr + | 618 | sc->sc_txq.t_physaddr = sc->sc_rxq.r_physaddr + | |
619 | AWGE_RX_RING_COUNT*sizeof(struct dwc_gmac_dev_dmadesc); | 619 | AWGE_RX_RING_COUNT*sizeof(struct dwc_gmac_dev_dmadesc); | |
620 | 620 | |||
621 | return 0; | 621 | return 0; | |
622 | 622 | |||
623 | fail: | 623 | fail: | |
624 | dwc_gmac_free_dma_rings(sc); | 624 | dwc_gmac_free_dma_rings(sc); | |
625 | return error; | 625 | return error; | |
626 | } | 626 | } | |
627 | 627 | |||
628 | static void | 628 | static void | |
629 | dwc_gmac_free_dma_rings(struct dwc_gmac_softc *sc) | 629 | dwc_gmac_free_dma_rings(struct dwc_gmac_softc *sc) | |
630 | { | 630 | { | |
631 | bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_ring_map, 0, | 631 | bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_ring_map, 0, | |
632 | sc->sc_dma_ring_map->dm_mapsize, BUS_DMASYNC_POSTWRITE); | 632 | sc->sc_dma_ring_map->dm_mapsize, BUS_DMASYNC_POSTWRITE); | |
633 | bus_dmamap_unload(sc->sc_dmat, sc->sc_dma_ring_map); | 633 | bus_dmamap_unload(sc->sc_dmat, sc->sc_dma_ring_map); | |
634 | bus_dmamem_unmap(sc->sc_dmat, sc->sc_rxq.r_desc, | 634 | bus_dmamem_unmap(sc->sc_dmat, sc->sc_rxq.r_desc, | |
635 | AWGE_TOTAL_RING_COUNT * sizeof(struct dwc_gmac_dev_dmadesc)); | 635 | AWGE_TOTAL_RING_COUNT * sizeof(struct dwc_gmac_dev_dmadesc)); | |
636 | bus_dmamem_free(sc->sc_dmat, &sc->sc_dma_ring_seg, 1); | 636 | bus_dmamem_free(sc->sc_dmat, &sc->sc_dma_ring_seg, 1); | |
637 | } | 637 | } | |
638 | 638 | |||
639 | static void | 639 | static void | |
640 | dwc_gmac_free_rx_ring(struct dwc_gmac_softc *sc, struct dwc_gmac_rx_ring *ring) | 640 | dwc_gmac_free_rx_ring(struct dwc_gmac_softc *sc, struct dwc_gmac_rx_ring *ring) | |
641 | { | 641 | { | |
642 | struct dwc_gmac_rx_data *data; | 642 | struct dwc_gmac_rx_data *data; | |
643 | int i; | 643 | int i; | |
644 | 644 | |||
645 | if (ring->r_desc == NULL) | 645 | if (ring->r_desc == NULL) | |
646 | return; | 646 | return; | |
647 | 647 | |||
648 | 648 | |||
649 | for (i = 0; i < AWGE_RX_RING_COUNT; i++) { | 649 | for (i = 0; i < AWGE_RX_RING_COUNT; i++) { | |
650 | data = &ring->r_data[i]; | 650 | data = &ring->r_data[i]; | |
651 | 651 | |||
652 | if (data->rd_map != NULL) { | 652 | if (data->rd_map != NULL) { | |
653 | bus_dmamap_sync(sc->sc_dmat, data->rd_map, 0, | 653 | bus_dmamap_sync(sc->sc_dmat, data->rd_map, 0, | |
654 | AWGE_RX_RING_COUNT | 654 | AWGE_RX_RING_COUNT | |
655 | *sizeof(struct dwc_gmac_dev_dmadesc), | 655 | *sizeof(struct dwc_gmac_dev_dmadesc), | |
656 | BUS_DMASYNC_POSTREAD); | 656 | BUS_DMASYNC_POSTREAD); | |
657 | bus_dmamap_unload(sc->sc_dmat, data->rd_map); | 657 | bus_dmamap_unload(sc->sc_dmat, data->rd_map); | |
658 | bus_dmamap_destroy(sc->sc_dmat, data->rd_map); | 658 | bus_dmamap_destroy(sc->sc_dmat, data->rd_map); | |
659 | } | 659 | } | |
660 | if (data->rd_m != NULL) | 660 | if (data->rd_m != NULL) | |
661 | m_freem(data->rd_m); | 661 | m_freem(data->rd_m); | |
662 | } | 662 | } | |
663 | } | 663 | } | |
664 | 664 | |||
665 | static int | 665 | static int | |
666 | dwc_gmac_alloc_tx_ring(struct dwc_gmac_softc *sc, | 666 | dwc_gmac_alloc_tx_ring(struct dwc_gmac_softc *sc, | |
667 | struct dwc_gmac_tx_ring *ring) | 667 | struct dwc_gmac_tx_ring *ring) | |
668 | { | 668 | { | |
669 | int i, error = 0; | 669 | int i, error = 0; | |
670 | 670 | |||
671 | ring->t_queued = 0; | 671 | ring->t_queued = 0; | |
672 | ring->t_cur = ring->t_next = 0; | 672 | ring->t_cur = ring->t_next = 0; | |
673 | 673 | |||
674 | memset(ring->t_desc, 0, AWGE_TX_RING_COUNT*sizeof(*ring->t_desc)); | 674 | memset(ring->t_desc, 0, AWGE_TX_RING_COUNT*sizeof(*ring->t_desc)); | |
675 | bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_ring_map, | 675 | bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_ring_map, | |
676 | TX_DESC_OFFSET(0), | 676 | TX_DESC_OFFSET(0), | |
677 | AWGE_TX_RING_COUNT*sizeof(struct dwc_gmac_dev_dmadesc), | 677 | AWGE_TX_RING_COUNT*sizeof(struct dwc_gmac_dev_dmadesc), | |
678 | BUS_DMASYNC_POSTWRITE); | 678 | BUS_DMASYNC_POSTWRITE); | |
679 | 679 | |||
680 | for (i = 0; i < AWGE_TX_RING_COUNT; i++) { | 680 | for (i = 0; i < AWGE_TX_RING_COUNT; i++) { | |
681 | error = bus_dmamap_create(sc->sc_dmat, MCLBYTES, | 681 | error = bus_dmamap_create(sc->sc_dmat, MCLBYTES, | |
682 | AWGE_TX_RING_COUNT, MCLBYTES, 0, | 682 | AWGE_TX_RING_COUNT, MCLBYTES, 0, | |
683 | BUS_DMA_NOWAIT | BUS_DMA_COHERENT, | 683 | BUS_DMA_NOWAIT | BUS_DMA_COHERENT, | |
684 | &ring->t_data[i].td_map); | 684 | &ring->t_data[i].td_map); | |
685 | if (error != 0) { | 685 | if (error != 0) { | |
686 | aprint_error_dev(sc->sc_dev, | 686 | aprint_error_dev(sc->sc_dev, | |
687 | "could not create TX DMA map #%d\n", i); | 687 | "could not create TX DMA map #%d\n", i); | |
688 | ring->t_data[i].td_map = NULL; | 688 | ring->t_data[i].td_map = NULL; | |
689 | goto fail; | 689 | goto fail; | |
690 | } | 690 | } | |
691 | ring->t_desc[i].ddesc_next = htole32( | 691 | ring->t_desc[i].ddesc_next = htole32( | |
692 | ring->t_physaddr + sizeof(struct dwc_gmac_dev_dmadesc) | 692 | ring->t_physaddr + sizeof(struct dwc_gmac_dev_dmadesc) | |
693 | *TX_NEXT(i)); | 693 | *TX_NEXT(i)); | |
694 | } | 694 | } | |
695 | 695 | |||
696 | return 0; | 696 | return 0; | |
697 | 697 | |||
698 | fail: | 698 | fail: | |
699 | dwc_gmac_free_tx_ring(sc, ring); | 699 | dwc_gmac_free_tx_ring(sc, ring); | |
700 | return error; | 700 | return error; | |
701 | } | 701 | } | |
702 | 702 | |||
703 | static void | 703 | static void | |
704 | dwc_gmac_txdesc_sync(struct dwc_gmac_softc *sc, int start, int end, int ops) | 704 | dwc_gmac_txdesc_sync(struct dwc_gmac_softc *sc, int start, int end, int ops) | |
705 | { | 705 | { | |
706 | /* 'end' is pointing one descriptor beyond the last we want to sync */ | 706 | /* 'end' is pointing one descriptor beyond the last we want to sync */ | |
707 | if (end > start) { | 707 | if (end > start) { | |
708 | bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_ring_map, | 708 | bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_ring_map, | |
709 | TX_DESC_OFFSET(start), | 709 | TX_DESC_OFFSET(start), | |
710 | TX_DESC_OFFSET(end)-TX_DESC_OFFSET(start), | 710 | TX_DESC_OFFSET(end)-TX_DESC_OFFSET(start), | |
711 | ops); | 711 | ops); | |
712 | return; | 712 | return; | |
713 | } | 713 | } | |
714 | /* sync from 'start' to end of ring */ | 714 | /* sync from 'start' to end of ring */ | |
715 | bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_ring_map, | 715 | bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_ring_map, | |
716 | TX_DESC_OFFSET(start), | 716 | TX_DESC_OFFSET(start), | |
717 | TX_DESC_OFFSET(AWGE_TX_RING_COUNT)-TX_DESC_OFFSET(start), | 717 | TX_DESC_OFFSET(AWGE_TX_RING_COUNT)-TX_DESC_OFFSET(start), | |
718 | ops); | 718 | ops); | |
719 | if (TX_DESC_OFFSET(end) - TX_DESC_OFFSET(0) > 0) { | 719 | if (TX_DESC_OFFSET(end) - TX_DESC_OFFSET(0) > 0) { | |
720 | /* sync from start of ring to 'end' */ | 720 | /* sync from start of ring to 'end' */ | |
721 | bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_ring_map, | 721 | bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_ring_map, | |
722 | TX_DESC_OFFSET(0), | 722 | TX_DESC_OFFSET(0), | |
723 | TX_DESC_OFFSET(end)-TX_DESC_OFFSET(0), | 723 | TX_DESC_OFFSET(end)-TX_DESC_OFFSET(0), | |
724 | ops); | 724 | ops); | |
725 | } | 725 | } | |
726 | } | 726 | } | |
727 | 727 | |||
728 | static void | 728 | static void | |
729 | dwc_gmac_reset_tx_ring(struct dwc_gmac_softc *sc, | 729 | dwc_gmac_reset_tx_ring(struct dwc_gmac_softc *sc, | |
730 | struct dwc_gmac_tx_ring *ring) | 730 | struct dwc_gmac_tx_ring *ring) | |
731 | { | 731 | { | |
732 | int i; | 732 | int i; | |
733 | 733 | |||
734 | mutex_enter(&ring->t_mtx); | 734 | mutex_enter(&ring->t_mtx); | |
735 | for (i = 0; i < AWGE_TX_RING_COUNT; i++) { | 735 | for (i = 0; i < AWGE_TX_RING_COUNT; i++) { | |
736 | struct dwc_gmac_tx_data *data = &ring->t_data[i]; | 736 | struct dwc_gmac_tx_data *data = &ring->t_data[i]; | |
737 | 737 | |||
738 | if (data->td_m != NULL) { | 738 | if (data->td_m != NULL) { | |
739 | bus_dmamap_sync(sc->sc_dmat, data->td_active, | 739 | bus_dmamap_sync(sc->sc_dmat, data->td_active, | |
740 | 0, data->td_active->dm_mapsize, | 740 | 0, data->td_active->dm_mapsize, | |
741 | BUS_DMASYNC_POSTWRITE); | 741 | BUS_DMASYNC_POSTWRITE); | |
742 | bus_dmamap_unload(sc->sc_dmat, data->td_active); | 742 | bus_dmamap_unload(sc->sc_dmat, data->td_active); | |
743 | m_freem(data->td_m); | 743 | m_freem(data->td_m); | |
744 | data->td_m = NULL; | 744 | data->td_m = NULL; | |
745 | } | 745 | } | |
746 | } | 746 | } | |
747 | 747 | |||
748 | bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_ring_map, | 748 | bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_ring_map, | |
749 | TX_DESC_OFFSET(0), | 749 | TX_DESC_OFFSET(0), | |
750 | AWGE_TX_RING_COUNT*sizeof(struct dwc_gmac_dev_dmadesc), | 750 | AWGE_TX_RING_COUNT*sizeof(struct dwc_gmac_dev_dmadesc), | |
751 | BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); | 751 | BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); | |
752 | bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_TX_ADDR, | 752 | bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_TX_ADDR, | |
753 | sc->sc_txq.t_physaddr); | 753 | sc->sc_txq.t_physaddr); | |
754 | 754 | |||
755 | ring->t_queued = 0; | 755 | ring->t_queued = 0; | |
756 | ring->t_cur = ring->t_next = 0; | 756 | ring->t_cur = ring->t_next = 0; | |
757 | mutex_exit(&ring->t_mtx); | 757 | mutex_exit(&ring->t_mtx); | |
758 | } | 758 | } | |
759 | 759 | |||
760 | static void | 760 | static void | |
761 | dwc_gmac_free_tx_ring(struct dwc_gmac_softc *sc, | 761 | dwc_gmac_free_tx_ring(struct dwc_gmac_softc *sc, | |
762 | struct dwc_gmac_tx_ring *ring) | 762 | struct dwc_gmac_tx_ring *ring) | |
763 | { | 763 | { | |
764 | int i; | 764 | int i; | |
765 | 765 | |||
766 | /* unload the maps */ | 766 | /* unload the maps */ | |
767 | for (i = 0; i < AWGE_TX_RING_COUNT; i++) { | 767 | for (i = 0; i < AWGE_TX_RING_COUNT; i++) { | |
768 | struct dwc_gmac_tx_data *data = &ring->t_data[i]; | 768 | struct dwc_gmac_tx_data *data = &ring->t_data[i]; | |
769 | 769 | |||
770 | if (data->td_m != NULL) { | 770 | if (data->td_m != NULL) { | |
771 | bus_dmamap_sync(sc->sc_dmat, data->td_active, | 771 | bus_dmamap_sync(sc->sc_dmat, data->td_active, | |
772 | 0, data->td_map->dm_mapsize, | 772 | 0, data->td_map->dm_mapsize, | |
773 | BUS_DMASYNC_POSTWRITE); | 773 | BUS_DMASYNC_POSTWRITE); | |
774 | bus_dmamap_unload(sc->sc_dmat, data->td_active); | 774 | bus_dmamap_unload(sc->sc_dmat, data->td_active); | |
775 | m_freem(data->td_m); | 775 | m_freem(data->td_m); | |
776 | data->td_m = NULL; | 776 | data->td_m = NULL; | |
777 | } | 777 | } | |
778 | } | 778 | } | |
779 | 779 | |||
780 | /* and actually free them */ | 780 | /* and actually free them */ | |
781 | for (i = 0; i < AWGE_TX_RING_COUNT; i++) { | 781 | for (i = 0; i < AWGE_TX_RING_COUNT; i++) { | |
782 | struct dwc_gmac_tx_data *data = &ring->t_data[i]; | 782 | struct dwc_gmac_tx_data *data = &ring->t_data[i]; | |
783 | 783 | |||
784 | bus_dmamap_destroy(sc->sc_dmat, data->td_map); | 784 | bus_dmamap_destroy(sc->sc_dmat, data->td_map); | |
785 | } | 785 | } | |
786 | } | 786 | } | |
787 | 787 | |||
788 | static void | 788 | static void | |
789 | dwc_gmac_miibus_statchg(struct ifnet *ifp) | 789 | dwc_gmac_miibus_statchg(struct ifnet *ifp) | |
790 | { | 790 | { | |
791 | struct dwc_gmac_softc * const sc = ifp->if_softc; | 791 | struct dwc_gmac_softc * const sc = ifp->if_softc; | |
792 | struct mii_data * const mii = &sc->sc_mii; | 792 | struct mii_data * const mii = &sc->sc_mii; | |
793 | uint32_t conf, flow; | 793 | uint32_t conf, flow; | |
794 | 794 | |||
795 | /* | 795 | /* | |
796 | * Set MII or GMII interface based on the speed | 796 | * Set MII or GMII interface based on the speed | |
797 | * negotiated by the PHY. | 797 | * negotiated by the PHY. | |
798 | */ | 798 | */ | |
799 | conf = bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_CONF); | 799 | conf = bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_CONF); | |
800 | conf &= ~(AWIN_GMAC_MAC_CONF_FES100 | AWIN_GMAC_MAC_CONF_MIISEL | 800 | conf &= ~(AWIN_GMAC_MAC_CONF_FES100 | AWIN_GMAC_MAC_CONF_MIISEL | |
801 | | AWIN_GMAC_MAC_CONF_FULLDPLX); | 801 | | AWIN_GMAC_MAC_CONF_FULLDPLX); | |
802 | conf |= AWIN_GMAC_MAC_CONF_FRAMEBURST | 802 | conf |= AWIN_GMAC_MAC_CONF_FRAMEBURST | |
803 | | AWIN_GMAC_MAC_CONF_DISABLERXOWN | 803 | | AWIN_GMAC_MAC_CONF_DISABLERXOWN | |
804 | | AWIN_GMAC_MAC_CONF_DISABLEJABBER | 804 | | AWIN_GMAC_MAC_CONF_DISABLEJABBER | |
805 | | AWIN_GMAC_MAC_CONF_ACS | 805 | | AWIN_GMAC_MAC_CONF_ACS | |
806 | | AWIN_GMAC_MAC_CONF_RXENABLE | 806 | | AWIN_GMAC_MAC_CONF_RXENABLE | |
807 | | AWIN_GMAC_MAC_CONF_TXENABLE; | 807 | | AWIN_GMAC_MAC_CONF_TXENABLE; | |
808 | switch (IFM_SUBTYPE(mii->mii_media_active)) { | 808 | switch (IFM_SUBTYPE(mii->mii_media_active)) { | |
809 | case IFM_10_T: | 809 | case IFM_10_T: | |
810 | conf |= AWIN_GMAC_MAC_CONF_MIISEL; | 810 | conf |= AWIN_GMAC_MAC_CONF_MIISEL; | |
811 | break; | 811 | break; | |
812 | case IFM_100_TX: | 812 | case IFM_100_TX: | |
813 | conf |= AWIN_GMAC_MAC_CONF_FES100 | | 813 | conf |= AWIN_GMAC_MAC_CONF_FES100 | | |
814 | AWIN_GMAC_MAC_CONF_MIISEL; | 814 | AWIN_GMAC_MAC_CONF_MIISEL; | |
815 | break; | 815 | break; | |
816 | case IFM_1000_T: | 816 | case IFM_1000_T: | |
817 | break; | 817 | break; | |
818 | } | 818 | } | |
819 | if (sc->sc_set_speed) | 819 | if (sc->sc_set_speed) | |
820 | sc->sc_set_speed(sc, IFM_SUBTYPE(mii->mii_media_active)); | 820 | sc->sc_set_speed(sc, IFM_SUBTYPE(mii->mii_media_active)); | |
821 | 821 | |||
822 | flow = 0; | 822 | flow = 0; | |
823 | if (IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) { | 823 | if (IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) { | |
824 | conf |= AWIN_GMAC_MAC_CONF_FULLDPLX; | 824 | conf |= AWIN_GMAC_MAC_CONF_FULLDPLX; | |
825 | flow |= __SHIFTIN(0x200, AWIN_GMAC_MAC_FLOWCTRL_PAUSE); | 825 | flow |= __SHIFTIN(0x200, AWIN_GMAC_MAC_FLOWCTRL_PAUSE); | |
826 | } | 826 | } | |
827 | if (mii->mii_media_active & IFM_ETH_TXPAUSE) { | 827 | if (mii->mii_media_active & IFM_ETH_TXPAUSE) { | |
828 | flow |= AWIN_GMAC_MAC_FLOWCTRL_TFE; | 828 | flow |= AWIN_GMAC_MAC_FLOWCTRL_TFE; | |
829 | } | 829 | } | |
830 | if (mii->mii_media_active & IFM_ETH_RXPAUSE) { | 830 | if (mii->mii_media_active & IFM_ETH_RXPAUSE) { | |
831 | flow |= AWIN_GMAC_MAC_FLOWCTRL_RFE; | 831 | flow |= AWIN_GMAC_MAC_FLOWCTRL_RFE; | |
832 | } | 832 | } | |
833 | bus_space_write_4(sc->sc_bst, sc->sc_bsh, | 833 | bus_space_write_4(sc->sc_bst, sc->sc_bsh, | |
834 | AWIN_GMAC_MAC_FLOWCTRL, flow); | 834 | AWIN_GMAC_MAC_FLOWCTRL, flow); | |
835 | 835 | |||
836 | #ifdef DWC_GMAC_DEBUG | 836 | #ifdef DWC_GMAC_DEBUG | |
837 | aprint_normal_dev(sc->sc_dev, | 837 | aprint_normal_dev(sc->sc_dev, | |
838 | "setting MAC conf register: %08x\n", conf); | 838 | "setting MAC conf register: %08x\n", conf); | |
839 | #endif | 839 | #endif | |
840 | 840 | |||
841 | bus_space_write_4(sc->sc_bst, sc->sc_bsh, | 841 | bus_space_write_4(sc->sc_bst, sc->sc_bsh, | |
842 | AWIN_GMAC_MAC_CONF, conf); | 842 | AWIN_GMAC_MAC_CONF, conf); | |
843 | } | 843 | } | |
844 | 844 | |||
845 | static int | 845 | static int | |
846 | dwc_gmac_init(struct ifnet *ifp) | 846 | dwc_gmac_init(struct ifnet *ifp) | |
847 | { | 847 | { | |
848 | struct dwc_gmac_softc *sc = ifp->if_softc; | 848 | struct dwc_gmac_softc *sc = ifp->if_softc; | |
849 | 849 | |||
850 | mutex_enter(sc->sc_lock); | 850 | mutex_enter(sc->sc_lock); | |
851 | int ret = dwc_gmac_init_locked(ifp); | 851 | int ret = dwc_gmac_init_locked(ifp); | |
852 | mutex_exit(sc->sc_lock); | 852 | mutex_exit(sc->sc_lock); | |
853 | 853 | |||
854 | return ret; | 854 | return ret; | |
855 | } | 855 | } | |
856 | 856 | |||
857 | static int | 857 | static int | |
858 | dwc_gmac_init_locked(struct ifnet *ifp) | 858 | dwc_gmac_init_locked(struct ifnet *ifp) | |
859 | { | 859 | { | |
860 | struct dwc_gmac_softc *sc = ifp->if_softc; | 860 | struct dwc_gmac_softc *sc = ifp->if_softc; | |
861 | uint32_t ffilt; | 861 | uint32_t ffilt; | |
862 | 862 | |||
863 | if (ifp->if_flags & IFF_RUNNING) | 863 | if (ifp->if_flags & IFF_RUNNING) | |
864 | return 0; | 864 | return 0; | |
865 | 865 | |||
866 | dwc_gmac_stop_locked(ifp, 0); | 866 | dwc_gmac_stop_locked(ifp, 0); | |
867 | 867 | |||
868 | /* | 868 | /* | |
869 | * Configure DMA burst/transfer mode and RX/TX priorities. | 869 | * Configure DMA burst/transfer mode and RX/TX priorities. | |
870 | * XXX - the GMAC_BUSMODE_PRIORXTX bits are undocumented. | 870 | * XXX - the GMAC_BUSMODE_PRIORXTX bits are undocumented. | |
871 | */ | 871 | */ | |
872 | bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_BUSMODE, | 872 | bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_BUSMODE, | |
873 | GMAC_BUSMODE_FIXEDBURST | GMAC_BUSMODE_4PBL | | 873 | GMAC_BUSMODE_FIXEDBURST | GMAC_BUSMODE_4PBL | | |
874 | __SHIFTIN(2, GMAC_BUSMODE_RPBL) | | 874 | __SHIFTIN(2, GMAC_BUSMODE_RPBL) | | |
875 | __SHIFTIN(2, GMAC_BUSMODE_PBL)); | 875 | __SHIFTIN(2, GMAC_BUSMODE_PBL)); | |
876 | 876 | |||
877 | /* | 877 | /* | |
878 | * Set up address filter | 878 | * Set up address filter | |
879 | */ | 879 | */ | |
880 | ffilt = bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_FFILT); | 880 | ffilt = bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_FFILT); | |
881 | if (ifp->if_flags & IFF_PROMISC) { | 881 | if (ifp->if_flags & IFF_PROMISC) { | |
882 | ffilt |= AWIN_GMAC_MAC_FFILT_PR; | 882 | ffilt |= AWIN_GMAC_MAC_FFILT_PR; | |
883 | } else { | 883 | } else { | |
884 | ffilt &= ~AWIN_GMAC_MAC_FFILT_PR; | 884 | ffilt &= ~AWIN_GMAC_MAC_FFILT_PR; | |
885 | } | 885 | } | |
886 | if (ifp->if_flags & IFF_BROADCAST) { | 886 | if (ifp->if_flags & IFF_BROADCAST) { | |
887 | ffilt &= ~AWIN_GMAC_MAC_FFILT_DBF; | 887 | ffilt &= ~AWIN_GMAC_MAC_FFILT_DBF; | |
888 | } else { | 888 | } else { | |
889 | ffilt |= AWIN_GMAC_MAC_FFILT_DBF; | 889 | ffilt |= AWIN_GMAC_MAC_FFILT_DBF; | |
890 | } | 890 | } | |
891 | bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_FFILT, ffilt); | 891 | bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_FFILT, ffilt); | |
892 | 892 | |||
893 | /* | 893 | /* | |
894 | * Set up multicast filter | 894 | * Set up multicast filter | |
895 | */ | 895 | */ | |
896 | dwc_gmac_setmulti(sc); | 896 | dwc_gmac_setmulti(sc); | |
897 | 897 | |||
898 | /* | 898 | /* | |
899 | * Set up dma pointer for RX and TX ring | 899 | * Set up dma pointer for RX and TX ring | |
900 | */ | 900 | */ | |
901 | bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_RX_ADDR, | 901 | bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_RX_ADDR, | |
902 | sc->sc_rxq.r_physaddr); | 902 | sc->sc_rxq.r_physaddr); | |
903 | bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_TX_ADDR, | 903 | bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_TX_ADDR, | |
904 | sc->sc_txq.t_physaddr); | 904 | sc->sc_txq.t_physaddr); | |
905 | 905 | |||
906 | /* | 906 | /* | |
907 | * Start RX/TX part | 907 | * Start RX/TX part | |
908 | */ | 908 | */ | |
909 | uint32_t opmode = GMAC_DMA_OP_RXSTART | GMAC_DMA_OP_TXSTART; | 909 | uint32_t opmode = GMAC_DMA_OP_RXSTART | GMAC_DMA_OP_TXSTART; | |
910 | if ((sc->sc_flags & DWC_GMAC_FORCE_THRESH_DMA_MODE) == 0) { | 910 | if ((sc->sc_flags & DWC_GMAC_FORCE_THRESH_DMA_MODE) == 0) { | |
911 | opmode |= GMAC_DMA_OP_RXSTOREFORWARD | GMAC_DMA_OP_TXSTOREFORWARD; | 911 | opmode |= GMAC_DMA_OP_RXSTOREFORWARD | GMAC_DMA_OP_TXSTOREFORWARD; | |
912 | } | 912 | } | |
913 | bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_OPMODE, opmode); | 913 | bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_OPMODE, opmode); | |
914 | 914 | |||
915 | sc->sc_stopping = false; | 915 | sc->sc_stopping = false; | |
916 | 916 | |||
917 | ifp->if_flags |= IFF_RUNNING; | 917 | ifp->if_flags |= IFF_RUNNING; | |
918 | ifp->if_flags &= ~IFF_OACTIVE; | 918 | ifp->if_flags &= ~IFF_OACTIVE; | |
919 | 919 | |||
920 | return 0; | 920 | return 0; | |
921 | } | 921 | } | |
922 | 922 | |||
923 | static void | 923 | static void | |
924 | dwc_gmac_start(struct ifnet *ifp) | 924 | dwc_gmac_start(struct ifnet *ifp) | |
925 | { | 925 | { | |
926 | struct dwc_gmac_softc *sc = ifp->if_softc; | 926 | struct dwc_gmac_softc *sc = ifp->if_softc; | |
927 | #ifdef DWCGMAC_MPSAFE | 927 | #ifdef DWCGMAC_MPSAFE | |
928 | KASSERT(if_is_mpsafe(ifp)); | 928 | KASSERT(if_is_mpsafe(ifp)); | |
929 | #endif | 929 | #endif | |
930 | 930 | |||
931 | mutex_enter(sc->sc_lock); | 931 | mutex_enter(sc->sc_lock); | |
932 | if (!sc->sc_stopping) { | 932 | if (!sc->sc_stopping) { | |
933 | mutex_enter(&sc->sc_txq.t_mtx); | 933 | mutex_enter(&sc->sc_txq.t_mtx); | |
934 | dwc_gmac_start_locked(ifp); | 934 | dwc_gmac_start_locked(ifp); | |
935 | mutex_exit(&sc->sc_txq.t_mtx); | 935 | mutex_exit(&sc->sc_txq.t_mtx); | |
936 | } | 936 | } | |
937 | mutex_exit(sc->sc_lock); | 937 | mutex_exit(sc->sc_lock); | |
938 | } | 938 | } | |
939 | 939 | |||
940 | static void | 940 | static void | |
941 | dwc_gmac_start_locked(struct ifnet *ifp) | 941 | dwc_gmac_start_locked(struct ifnet *ifp) | |
942 | { | 942 | { | |
943 | struct dwc_gmac_softc *sc = ifp->if_softc; | 943 | struct dwc_gmac_softc *sc = ifp->if_softc; | |
944 | int old = sc->sc_txq.t_queued; | 944 | int old = sc->sc_txq.t_queued; | |
945 | int start = sc->sc_txq.t_cur; | 945 | int start = sc->sc_txq.t_cur; | |
946 | struct mbuf *m0; | 946 | struct mbuf *m0; | |
947 | 947 | |||
948 | if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING) | 948 | if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING) | |
949 | return; | 949 | return; | |
950 | 950 | |||
951 | for (;;) { | 951 | for (;;) { | |
952 | IFQ_POLL(&ifp->if_snd, m0); | 952 | IFQ_POLL(&ifp->if_snd, m0); | |
953 | if (m0 == NULL) | 953 | if (m0 == NULL) | |
954 | break; | 954 | break; | |
955 | if (dwc_gmac_queue(sc, m0) != 0) { | 955 | if (dwc_gmac_queue(sc, m0) != 0) { | |
956 | ifp->if_flags |= IFF_OACTIVE; | 956 | ifp->if_flags |= IFF_OACTIVE; | |
957 | break; | 957 | break; | |
958 | } | 958 | } | |
959 | IFQ_DEQUEUE(&ifp->if_snd, m0); | 959 | IFQ_DEQUEUE(&ifp->if_snd, m0); | |
960 | bpf_mtap(ifp, m0, BPF_D_OUT); | 960 | bpf_mtap(ifp, m0, BPF_D_OUT); | |
961 | if (sc->sc_txq.t_queued == AWGE_TX_RING_COUNT) { | 961 | if (sc->sc_txq.t_queued == AWGE_TX_RING_COUNT) { | |
962 | ifp->if_flags |= IFF_OACTIVE; | 962 | ifp->if_flags |= IFF_OACTIVE; | |
963 | break; | 963 | break; | |
964 | } | 964 | } | |
965 | } | 965 | } | |
966 | 966 | |||
967 | if (sc->sc_txq.t_queued != old) { | 967 | if (sc->sc_txq.t_queued != old) { | |
968 | /* packets have been queued, kick it off */ | 968 | /* packets have been queued, kick it off */ | |
969 | dwc_gmac_txdesc_sync(sc, start, sc->sc_txq.t_cur, | 969 | dwc_gmac_txdesc_sync(sc, start, sc->sc_txq.t_cur, | |
970 | BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); | 970 | BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); | |
971 | 971 | |||
972 | #ifdef DWC_GMAC_DEBUG | 972 | #ifdef DWC_GMAC_DEBUG | |
973 | dwc_dump_status(sc); | 973 | dwc_dump_status(sc); | |
974 | #endif | 974 | #endif | |
975 | bus_space_write_4(sc->sc_bst, sc->sc_bsh, | 975 | bus_space_write_4(sc->sc_bst, sc->sc_bsh, | |
976 | AWIN_GMAC_DMA_TXPOLL, ~0U); | 976 | AWIN_GMAC_DMA_TXPOLL, ~0U); | |
977 | } | 977 | } | |
978 | } | 978 | } | |
979 | 979 | |||
980 | static void | 980 | static void | |
981 | dwc_gmac_stop(struct ifnet *ifp, int disable) | 981 | dwc_gmac_stop(struct ifnet *ifp, int disable) | |
982 | { | 982 | { | |
983 | struct dwc_gmac_softc *sc = ifp->if_softc; | 983 | struct dwc_gmac_softc *sc = ifp->if_softc; | |
984 | 984 | |||
985 | mutex_enter(sc->sc_lock); | 985 | mutex_enter(sc->sc_lock); | |
986 | dwc_gmac_stop_locked(ifp, disable); | 986 | dwc_gmac_stop_locked(ifp, disable); | |
987 | mutex_exit(sc->sc_lock); | 987 | mutex_exit(sc->sc_lock); | |
988 | } | 988 | } | |
989 | 989 | |||
990 | static void | 990 | static void | |
991 | dwc_gmac_stop_locked(struct ifnet *ifp, int disable) | 991 | dwc_gmac_stop_locked(struct ifnet *ifp, int disable) | |
992 | { | 992 | { | |
993 | struct dwc_gmac_softc *sc = ifp->if_softc; | 993 | struct dwc_gmac_softc *sc = ifp->if_softc; | |
994 | 994 | |||
995 | sc->sc_stopping = true; | 995 | sc->sc_stopping = true; | |
996 | 996 | |||
997 | bus_space_write_4(sc->sc_bst, sc->sc_bsh, | 997 | bus_space_write_4(sc->sc_bst, sc->sc_bsh, | |
998 | AWIN_GMAC_DMA_OPMODE, | 998 | AWIN_GMAC_DMA_OPMODE, | |
999 | bus_space_read_4(sc->sc_bst, sc->sc_bsh, | 999 | bus_space_read_4(sc->sc_bst, sc->sc_bsh, | |
1000 | AWIN_GMAC_DMA_OPMODE) | 1000 | AWIN_GMAC_DMA_OPMODE) | |
1001 | & ~(GMAC_DMA_OP_TXSTART | GMAC_DMA_OP_RXSTART)); | 1001 | & ~(GMAC_DMA_OP_TXSTART | GMAC_DMA_OP_RXSTART)); | |
1002 | bus_space_write_4(sc->sc_bst, sc->sc_bsh, | 1002 | bus_space_write_4(sc->sc_bst, sc->sc_bsh, | |
1003 | AWIN_GMAC_DMA_OPMODE, | 1003 | AWIN_GMAC_DMA_OPMODE, | |
1004 | bus_space_read_4(sc->sc_bst, sc->sc_bsh, | 1004 | bus_space_read_4(sc->sc_bst, sc->sc_bsh, | |
1005 | AWIN_GMAC_DMA_OPMODE) | GMAC_DMA_OP_FLUSHTX); | 1005 | AWIN_GMAC_DMA_OPMODE) | GMAC_DMA_OP_FLUSHTX); | |
1006 | 1006 | |||
1007 | mii_down(&sc->sc_mii); | 1007 | mii_down(&sc->sc_mii); | |
1008 | dwc_gmac_reset_tx_ring(sc, &sc->sc_txq); | 1008 | dwc_gmac_reset_tx_ring(sc, &sc->sc_txq); | |
1009 | dwc_gmac_reset_rx_ring(sc, &sc->sc_rxq); | 1009 | dwc_gmac_reset_rx_ring(sc, &sc->sc_rxq); | |
1010 | 1010 | |||
1011 | ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); | 1011 | ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); | |
1012 | } | 1012 | } | |
1013 | 1013 | |||
1014 | /* | 1014 | /* | |
1015 | * Add m0 to the TX ring | 1015 | * Add m0 to the TX ring | |
1016 | */ | 1016 | */ | |
1017 | static int | 1017 | static int | |
1018 | dwc_gmac_queue(struct dwc_gmac_softc *sc, struct mbuf *m0) | 1018 | dwc_gmac_queue(struct dwc_gmac_softc *sc, struct mbuf *m0) | |
1019 | { | 1019 | { | |
1020 | struct dwc_gmac_dev_dmadesc *desc = NULL; | 1020 | struct dwc_gmac_dev_dmadesc *desc = NULL; | |
1021 | struct dwc_gmac_tx_data *data = NULL; | 1021 | struct dwc_gmac_tx_data *data = NULL; | |
1022 | bus_dmamap_t map; | 1022 | bus_dmamap_t map; | |
1023 | int error, i, first; | 1023 | int error, i, first; | |
1024 | 1024 | |||
1025 | #ifdef DWC_GMAC_DEBUG | 1025 | #ifdef DWC_GMAC_DEBUG | |
1026 | aprint_normal_dev(sc->sc_dev, | 1026 | aprint_normal_dev(sc->sc_dev, | |
1027 | "dwc_gmac_queue: adding mbuf chain %p\n", m0); | 1027 | "dwc_gmac_queue: adding mbuf chain %p\n", m0); | |
1028 | #endif | 1028 | #endif | |
1029 | 1029 | |||
1030 | first = sc->sc_txq.t_cur; | 1030 | first = sc->sc_txq.t_cur; | |
1031 | map = sc->sc_txq.t_data[first].td_map; | 1031 | map = sc->sc_txq.t_data[first].td_map; | |
1032 | 1032 | |||
1033 | error = bus_dmamap_load_mbuf(sc->sc_dmat, map, m0, | 1033 | error = bus_dmamap_load_mbuf(sc->sc_dmat, map, m0, | |
1034 | BUS_DMA_WRITE | BUS_DMA_NOWAIT); | 1034 | BUS_DMA_WRITE | BUS_DMA_NOWAIT); | |
1035 | if (error != 0) { | 1035 | if (error != 0) { | |
1036 | aprint_error_dev(sc->sc_dev, "could not map mbuf " | 1036 | aprint_error_dev(sc->sc_dev, "could not map mbuf " | |
1037 | "(len: %d, error %d)\n", m0->m_pkthdr.len, error); | 1037 | "(len: %d, error %d)\n", m0->m_pkthdr.len, error); | |
1038 | return error; | 1038 | return error; | |
1039 | } | 1039 | } | |
1040 | 1040 | |||
1041 | if (sc->sc_txq.t_queued + map->dm_nsegs > AWGE_TX_RING_COUNT) { | 1041 | if (sc->sc_txq.t_queued + map->dm_nsegs > AWGE_TX_RING_COUNT) { | |
1042 | bus_dmamap_unload(sc->sc_dmat, map); | 1042 | bus_dmamap_unload(sc->sc_dmat, map); | |
1043 | return ENOBUFS; | 1043 | return ENOBUFS; | |
1044 | } | 1044 | } | |
1045 | 1045 | |||
1046 | for (i = 0; i < map->dm_nsegs; i++) { | 1046 | for (i = 0; i < map->dm_nsegs; i++) { | |
1047 | data = &sc->sc_txq.t_data[sc->sc_txq.t_cur]; | 1047 | data = &sc->sc_txq.t_data[sc->sc_txq.t_cur]; | |
1048 | desc = &sc->sc_txq.t_desc[sc->sc_txq.t_cur]; | 1048 | desc = &sc->sc_txq.t_desc[sc->sc_txq.t_cur]; | |
1049 | 1049 | |||
1050 | desc->ddesc_data = htole32(map->dm_segs[i].ds_addr); | 1050 | desc->ddesc_data = htole32(map->dm_segs[i].ds_addr); | |
1051 | 1051 | |||
1052 | #ifdef DWC_GMAC_DEBUG | 1052 | #ifdef DWC_GMAC_DEBUG | |
1053 | aprint_normal_dev(sc->sc_dev, "enqueing desc #%d data %08lx " | 1053 | aprint_normal_dev(sc->sc_dev, "enqueing desc #%d data %08lx " | |
1054 | "len %lu\n", sc->sc_txq.t_cur, | 1054 | "len %lu\n", sc->sc_txq.t_cur, | |
1055 | (unsigned long)map->dm_segs[i].ds_addr, | 1055 | (unsigned long)map->dm_segs[i].ds_addr, | |
1056 | (unsigned long)map->dm_segs[i].ds_len); | 1056 | (unsigned long)map->dm_segs[i].ds_len); | |
1057 | #endif | 1057 | #endif | |
1058 | 1058 | |||
1059 | sc->sc_descm->tx_init_flags(desc); | 1059 | sc->sc_descm->tx_init_flags(desc); | |
1060 | sc->sc_descm->tx_set_len(desc, map->dm_segs[i].ds_len); | 1060 | sc->sc_descm->tx_set_len(desc, map->dm_segs[i].ds_len); | |
1061 | 1061 | |||
1062 | if (i == 0) | 1062 | if (i == 0) | |
1063 | sc->sc_descm->tx_set_first_frag(desc); | 1063 | sc->sc_descm->tx_set_first_frag(desc); | |
1064 | 1064 | |||
1065 | /* | 1065 | /* | |
1066 | * Defer passing ownership of the first descriptor | 1066 | * Defer passing ownership of the first descriptor | |
1067 | * until we are done. | 1067 | * until we are done. | |
1068 | */ | 1068 | */ | |
1069 | if (i != 0) | 1069 | if (i != 0) | |
1070 | sc->sc_descm->tx_set_owned_by_dev(desc); | 1070 | sc->sc_descm->tx_set_owned_by_dev(desc); | |
1071 | 1071 | |||
1072 | sc->sc_txq.t_queued++; | 1072 | sc->sc_txq.t_queued++; | |
1073 | sc->sc_txq.t_cur = TX_NEXT(sc->sc_txq.t_cur); | 1073 | sc->sc_txq.t_cur = TX_NEXT(sc->sc_txq.t_cur); | |
1074 | } | 1074 | } | |
1075 | 1075 | |||
1076 | sc->sc_descm->tx_set_last_frag(desc); | 1076 | sc->sc_descm->tx_set_last_frag(desc); | |
1077 | 1077 | |||
1078 | data->td_m = m0; | 1078 | data->td_m = m0; | |
1079 | data->td_active = map; | 1079 | data->td_active = map; | |
1080 | 1080 | |||
1081 | bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize, | 1081 | bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize, | |
1082 | BUS_DMASYNC_PREWRITE); | 1082 | BUS_DMASYNC_PREWRITE); | |
1083 | 1083 | |||
1084 | /* Pass first to device */ | 1084 | /* Pass first to device */ | |
1085 | sc->sc_descm->tx_set_owned_by_dev(&sc->sc_txq.t_desc[first]); | 1085 | sc->sc_descm->tx_set_owned_by_dev(&sc->sc_txq.t_desc[first]); | |
1086 | 1086 | |||
1087 | bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize, | 1087 | bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize, | |
1088 | BUS_DMASYNC_PREWRITE); | 1088 | BUS_DMASYNC_PREWRITE); | |
1089 | 1089 | |||
1090 | return 0; | 1090 | return 0; | |
1091 | } | 1091 | } | |
1092 | 1092 | |||
1093 | /* | 1093 | /* | |
1094 | * If the interface is up and running, only modify the receive | 1094 | * If the interface is up and running, only modify the receive | |
1095 | * filter when setting promiscuous or debug mode. Otherwise fall | 1095 | * filter when setting promiscuous or debug mode. Otherwise fall | |
1096 | * through to ether_ioctl, which will reset the chip. | 1096 | * through to ether_ioctl, which will reset the chip. | |
1097 | */ | 1097 | */ | |
1098 | static int | 1098 | static int | |
1099 | dwc_gmac_ifflags_cb(struct ethercom *ec) | 1099 | dwc_gmac_ifflags_cb(struct ethercom *ec) | |
1100 | { | 1100 | { | |
1101 | struct ifnet *ifp = &ec->ec_if; | 1101 | struct ifnet *ifp = &ec->ec_if; | |
1102 | struct dwc_gmac_softc *sc = ifp->if_softc; | 1102 | struct dwc_gmac_softc *sc = ifp->if_softc; | |
1103 | int ret = 0; | 1103 | int ret = 0; | |
1104 | 1104 | |||
1105 | mutex_enter(sc->sc_lock); | 1105 | mutex_enter(sc->sc_lock); | |
1106 | u_short change = ifp->if_flags ^ sc->sc_if_flags; | 1106 | u_short change = ifp->if_flags ^ sc->sc_if_flags; | |
1107 | sc->sc_if_flags = ifp->if_flags; | 1107 | sc->sc_if_flags = ifp->if_flags; | |
1108 | 1108 | |||
1109 | if ((change & ~(IFF_CANTCHANGE | IFF_DEBUG)) != 0) { | 1109 | if ((change & ~(IFF_CANTCHANGE | IFF_DEBUG)) != 0) { | |
1110 | ret = ENETRESET; | 1110 | ret = ENETRESET; | |
1111 | goto out; | 1111 | goto out; | |
1112 | } | 1112 | } | |
1113 | if ((change & IFF_PROMISC) != 0) { | 1113 | if ((change & IFF_PROMISC) != 0) { | |
1114 | dwc_gmac_setmulti(sc); | 1114 | dwc_gmac_setmulti(sc); | |
1115 | } | 1115 | } | |
1116 | out: | 1116 | out: | |
1117 | mutex_exit(sc->sc_lock); | 1117 | mutex_exit(sc->sc_lock); | |
1118 | 1118 | |||
1119 | return ret; | 1119 | return ret; | |
1120 | } | 1120 | } | |
1121 | 1121 | |||
1122 | static int | 1122 | static int | |
1123 | dwc_gmac_ioctl(struct ifnet *ifp, u_long cmd, void *data) | 1123 | dwc_gmac_ioctl(struct ifnet *ifp, u_long cmd, void *data) | |
1124 | { | 1124 | { | |
1125 | struct dwc_gmac_softc *sc = ifp->if_softc; | 1125 | struct dwc_gmac_softc *sc = ifp->if_softc; | |
1126 | int error = 0; | 1126 | int error = 0; | |
1127 | 1127 | |||
1128 | int s = splnet(); | 1128 | int s = splnet(); | |
1129 | error = ether_ioctl(ifp, cmd, data); | 1129 | error = ether_ioctl(ifp, cmd, data); | |
1130 | 1130 | |||
1131 | #ifdef DWCGMAC_MPSAFE | 1131 | #ifdef DWCGMAC_MPSAFE | |
1132 | splx(s); | 1132 | splx(s); | |
1133 | #endif | 1133 | #endif | |
1134 | 1134 | |||
1135 | if (error == ENETRESET) { | 1135 | if (error == ENETRESET) { | |
1136 | error = 0; | 1136 | error = 0; | |
1137 | if (cmd != SIOCADDMULTI && cmd != SIOCDELMULTI) | 1137 | if (cmd != SIOCADDMULTI && cmd != SIOCDELMULTI) | |
1138 | ; | 1138 | ; | |
1139 | else if (ifp->if_flags & IFF_RUNNING) { | 1139 | else if (ifp->if_flags & IFF_RUNNING) { | |
1140 | /* | 1140 | /* | |
1141 | * Multicast list has changed; set the hardware filter | 1141 | * Multicast list has changed; set the hardware filter | |
1142 | * accordingly. | 1142 | * accordingly. | |
1143 | */ | 1143 | */ | |
1144 | mutex_enter(sc->sc_lock); | 1144 | mutex_enter(sc->sc_lock); | |
1145 | dwc_gmac_setmulti(sc); | 1145 | dwc_gmac_setmulti(sc); | |
1146 | mutex_exit(sc->sc_lock); | 1146 | mutex_exit(sc->sc_lock); | |
1147 | } | 1147 | } | |
1148 | } | 1148 | } | |
1149 | 1149 | |||
1150 | /* Try to get things going again */ | 1150 | /* Try to get things going again */ | |
1151 | if (ifp->if_flags & IFF_UP) | 1151 | if (ifp->if_flags & IFF_UP) | |
1152 | dwc_gmac_start(ifp); | 1152 | dwc_gmac_start(ifp); | |
1153 | sc->sc_if_flags = sc->sc_ec.ec_if.if_flags; | 1153 | sc->sc_if_flags = sc->sc_ec.ec_if.if_flags; | |
1154 | 1154 | |||
1155 | #ifndef DWCGMAC_MPSAFE | 1155 | #ifndef DWCGMAC_MPSAFE | |
1156 | splx(s); | 1156 | splx(s); | |
1157 | #endif | 1157 | #endif | |
1158 | 1158 | |||
1159 | return error; | 1159 | return error; | |
1160 | } | 1160 | } | |
1161 | 1161 | |||
1162 | static void | 1162 | static void | |
1163 | dwc_gmac_tx_intr(struct dwc_gmac_softc *sc) | 1163 | dwc_gmac_tx_intr(struct dwc_gmac_softc *sc) | |
1164 | { | 1164 | { | |
1165 | struct ifnet *ifp = &sc->sc_ec.ec_if; | 1165 | struct ifnet *ifp = &sc->sc_ec.ec_if; | |
1166 | struct dwc_gmac_tx_data *data; | 1166 | struct dwc_gmac_tx_data *data; | |
1167 | struct dwc_gmac_dev_dmadesc *desc; | 1167 | struct dwc_gmac_dev_dmadesc *desc; | |
1168 | int i, nsegs; | 1168 | int i, nsegs; | |
1169 | 1169 | |||
1170 | mutex_enter(&sc->sc_txq.t_mtx); | 1170 | mutex_enter(&sc->sc_txq.t_mtx); | |
1171 | 1171 | |||
1172 | for (i = sc->sc_txq.t_next; sc->sc_txq.t_queued > 0; i = TX_NEXT(i)) { | 1172 | for (i = sc->sc_txq.t_next; sc->sc_txq.t_queued > 0; i = TX_NEXT(i)) { | |
1173 | #ifdef DWC_GMAC_DEBUG | 1173 | #ifdef DWC_GMAC_DEBUG | |
1174 | aprint_normal_dev(sc->sc_dev, | 1174 | aprint_normal_dev(sc->sc_dev, | |
1175 | "dwc_gmac_tx_intr: checking desc #%d (t_queued: %d)\n", | 1175 | "dwc_gmac_tx_intr: checking desc #%d (t_queued: %d)\n", | |
1176 | i, sc->sc_txq.t_queued); | 1176 | i, sc->sc_txq.t_queued); | |
1177 | #endif | 1177 | #endif | |
1178 | 1178 | |||
1179 | /* | 1179 | /* | |
1180 | * i+1 does not need to be a valid descriptor, | 1180 | * i+1 does not need to be a valid descriptor, | |
1181 | * this is just a special notion to just sync | 1181 | * this is just a special notion to just sync | |
1182 | * a single tx descriptor (i) | 1182 | * a single tx descriptor (i) | |
1183 | */ | 1183 | */ | |
1184 | dwc_gmac_txdesc_sync(sc, i, i+1, | 1184 | dwc_gmac_txdesc_sync(sc, i, i+1, | |
1185 | BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); | 1185 | BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); | |
1186 | 1186 | |||
1187 | desc = &sc->sc_txq.t_desc[i]; | 1187 | desc = &sc->sc_txq.t_desc[i]; | |
1188 | if (sc->sc_descm->tx_is_owned_by_dev(desc)) | 1188 | if (sc->sc_descm->tx_is_owned_by_dev(desc)) | |
1189 | break; | 1189 | break; | |
1190 | 1190 | |||
1191 | data = &sc->sc_txq.t_data[i]; | 1191 | data = &sc->sc_txq.t_data[i]; | |
1192 | if (data->td_m == NULL) | 1192 | if (data->td_m == NULL) | |
1193 | continue; | 1193 | continue; | |
1194 | 1194 | |||
1195 | ifp->if_opackets++; | 1195 | if_statinc(ifp, if_opackets); | |
1196 | nsegs = data->td_active->dm_nsegs; | 1196 | nsegs = data->td_active->dm_nsegs; | |
1197 | bus_dmamap_sync(sc->sc_dmat, data->td_active, 0, | 1197 | bus_dmamap_sync(sc->sc_dmat, data->td_active, 0, | |
1198 | data->td_active->dm_mapsize, BUS_DMASYNC_POSTWRITE); | 1198 | data->td_active->dm_mapsize, BUS_DMASYNC_POSTWRITE); | |
1199 | bus_dmamap_unload(sc->sc_dmat, data->td_active); | 1199 | bus_dmamap_unload(sc->sc_dmat, data->td_active); | |
1200 | 1200 | |||
1201 | #ifdef DWC_GMAC_DEBUG | 1201 | #ifdef DWC_GMAC_DEBUG | |
1202 | aprint_normal_dev(sc->sc_dev, | 1202 | aprint_normal_dev(sc->sc_dev, | |
1203 | "dwc_gmac_tx_intr: done with packet at desc #%d, " | 1203 | "dwc_gmac_tx_intr: done with packet at desc #%d, " | |
1204 | "freeing mbuf %p\n", i, data->td_m); | 1204 | "freeing mbuf %p\n", i, data->td_m); | |
1205 | #endif | 1205 | #endif | |
1206 | 1206 | |||
1207 | m_freem(data->td_m); | 1207 | m_freem(data->td_m); | |
1208 | data->td_m = NULL; | 1208 | data->td_m = NULL; | |
1209 | 1209 | |||
1210 | sc->sc_txq.t_queued -= nsegs; | 1210 | sc->sc_txq.t_queued -= nsegs; | |
1211 | } | 1211 | } | |
1212 | 1212 | |||
1213 | sc->sc_txq.t_next = i; | 1213 | sc->sc_txq.t_next = i; | |
1214 | 1214 | |||
1215 | if (sc->sc_txq.t_queued < AWGE_TX_RING_COUNT) { | 1215 | if (sc->sc_txq.t_queued < AWGE_TX_RING_COUNT) { | |
1216 | ifp->if_flags &= ~IFF_OACTIVE; | 1216 | ifp->if_flags &= ~IFF_OACTIVE; | |
1217 | } | 1217 | } | |
1218 | mutex_exit(&sc->sc_txq.t_mtx); | 1218 | mutex_exit(&sc->sc_txq.t_mtx); | |
1219 | } | 1219 | } | |
1220 | 1220 | |||
1221 | static void | 1221 | static void | |
1222 | dwc_gmac_rx_intr(struct dwc_gmac_softc *sc) | 1222 | dwc_gmac_rx_intr(struct dwc_gmac_softc *sc) | |
1223 | { | 1223 | { | |
1224 | struct ifnet *ifp = &sc->sc_ec.ec_if; | 1224 | struct ifnet *ifp = &sc->sc_ec.ec_if; | |
1225 | struct dwc_gmac_dev_dmadesc *desc; | 1225 | struct dwc_gmac_dev_dmadesc *desc; | |
1226 | struct dwc_gmac_rx_data *data; | 1226 | struct dwc_gmac_rx_data *data; | |
1227 | bus_addr_t physaddr; | 1227 | bus_addr_t physaddr; | |
1228 | struct mbuf *m, *mnew; | 1228 | struct mbuf *m, *mnew; | |
1229 | int i, len, error; | 1229 | int i, len, error; | |
1230 | 1230 | |||
1231 | mutex_enter(&sc->sc_rxq.r_mtx); | 1231 | mutex_enter(&sc->sc_rxq.r_mtx); | |
1232 | for (i = sc->sc_rxq.r_cur; ; i = RX_NEXT(i)) { | 1232 | for (i = sc->sc_rxq.r_cur; ; i = RX_NEXT(i)) { | |
1233 | bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_ring_map, | 1233 | bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_ring_map, | |
1234 | RX_DESC_OFFSET(i), sizeof(*desc), | 1234 | RX_DESC_OFFSET(i), sizeof(*desc), | |
1235 | BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); | 1235 | BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); | |
1236 | desc = &sc->sc_rxq.r_desc[i]; | 1236 | desc = &sc->sc_rxq.r_desc[i]; | |
1237 | data = &sc->sc_rxq.r_data[i]; | 1237 | data = &sc->sc_rxq.r_data[i]; | |
1238 | 1238 | |||
1239 | if (sc->sc_descm->rx_is_owned_by_dev(desc)) | 1239 | if (sc->sc_descm->rx_is_owned_by_dev(desc)) | |
1240 | break; | 1240 | break; | |
1241 | 1241 | |||
1242 | if (sc->sc_descm->rx_has_error(desc)) { | 1242 | if (sc->sc_descm->rx_has_error(desc)) { | |
1243 | #ifdef DWC_GMAC_DEBUG | 1243 | #ifdef DWC_GMAC_DEBUG | |
1244 | aprint_normal_dev(sc->sc_dev, | 1244 | aprint_normal_dev(sc->sc_dev, | |
1245 | "RX error: descriptor status %08x, skipping\n", | 1245 | "RX error: descriptor status %08x, skipping\n", | |
1246 | le32toh(desc->ddesc_status0)); | 1246 | le32toh(desc->ddesc_status0)); | |
1247 | #endif | 1247 | #endif | |
1248 | ifp->if_ierrors++; | 1248 | if_statinc(ifp, if_ierrors); | |
1249 | goto skip; | 1249 | goto skip; | |
1250 | } | 1250 | } | |
1251 | 1251 | |||
1252 | len = sc->sc_descm->rx_get_len(desc); | 1252 | len = sc->sc_descm->rx_get_len(desc); | |
1253 | 1253 | |||
1254 | #ifdef DWC_GMAC_DEBUG | 1254 | #ifdef DWC_GMAC_DEBUG | |
1255 | aprint_normal_dev(sc->sc_dev, | 1255 | aprint_normal_dev(sc->sc_dev, | |
1256 | "rx int: device is done with descriptor #%d, len: %d\n", | 1256 | "rx int: device is done with descriptor #%d, len: %d\n", | |
1257 | i, len); | 1257 | i, len); | |
1258 | #endif | 1258 | #endif | |
1259 | 1259 | |||
1260 | /* | 1260 | /* | |
1261 | * Try to get a new mbuf before passing this one | 1261 | * Try to get a new mbuf before passing this one | |
1262 | * up, if that fails, drop the packet and reuse | 1262 | * up, if that fails, drop the packet and reuse | |
1263 | * the existing one. | 1263 | * the existing one. | |
1264 | */ | 1264 | */ | |
1265 | MGETHDR(mnew, M_DONTWAIT, MT_DATA); | 1265 | MGETHDR(mnew, M_DONTWAIT, MT_DATA); | |
1266 | if (mnew == NULL) { | 1266 | if (mnew == NULL) { | |
1267 | ifp->if_ierrors++; | 1267 | if_statinc(ifp, if_ierrors); | |
1268 | goto skip; | 1268 | goto skip; | |
1269 | } | 1269 | } | |
1270 | MCLGET(mnew, M_DONTWAIT); | 1270 | MCLGET(mnew, M_DONTWAIT); | |
1271 | if ((mnew->m_flags & M_EXT) == 0) { | 1271 | if ((mnew->m_flags & M_EXT) == 0) { | |
1272 | m_freem(mnew); | 1272 | m_freem(mnew); | |
1273 | ifp->if_ierrors++; | 1273 | if_statinc(ifp, if_ierrors); | |
1274 | goto skip; | 1274 | goto skip; | |
1275 | } | 1275 | } | |
1276 | mnew->m_len = mnew->m_pkthdr.len = mnew->m_ext.ext_size; | 1276 | mnew->m_len = mnew->m_pkthdr.len = mnew->m_ext.ext_size; | |
1277 | if (mnew->m_len > AWGE_MAX_PACKET) { | 1277 | if (mnew->m_len > AWGE_MAX_PACKET) { | |
1278 | mnew->m_len = mnew->m_pkthdr.len = AWGE_MAX_PACKET; | 1278 | mnew->m_len = mnew->m_pkthdr.len = AWGE_MAX_PACKET; | |
1279 | } | 1279 | } | |
1280 | 1280 | |||
1281 | /* unload old DMA map */ | 1281 | /* unload old DMA map */ | |
1282 | bus_dmamap_sync(sc->sc_dmat, data->rd_map, 0, | 1282 | bus_dmamap_sync(sc->sc_dmat, data->rd_map, 0, | |
1283 | data->rd_map->dm_mapsize, BUS_DMASYNC_POSTREAD); | 1283 | data->rd_map->dm_mapsize, BUS_DMASYNC_POSTREAD); | |
1284 | bus_dmamap_unload(sc->sc_dmat, data->rd_map); | 1284 | bus_dmamap_unload(sc->sc_dmat, data->rd_map); | |
1285 | 1285 | |||
1286 | /* and reload with new mbuf */ | 1286 | /* and reload with new mbuf */ | |
1287 | error = bus_dmamap_load_mbuf(sc->sc_dmat, data->rd_map, | 1287 | error = bus_dmamap_load_mbuf(sc->sc_dmat, data->rd_map, | |
1288 | mnew, BUS_DMA_READ | BUS_DMA_NOWAIT); | 1288 | mnew, BUS_DMA_READ | BUS_DMA_NOWAIT); | |
1289 | if (error != 0) { | 1289 | if (error != 0) { | |
1290 | m_freem(mnew); | 1290 | m_freem(mnew); | |
1291 | /* try to reload old mbuf */ | 1291 | /* try to reload old mbuf */ | |
1292 | error = bus_dmamap_load_mbuf(sc->sc_dmat, data->rd_map, | 1292 | error = bus_dmamap_load_mbuf(sc->sc_dmat, data->rd_map, | |
1293 | data->rd_m, BUS_DMA_READ | BUS_DMA_NOWAIT); | 1293 | data->rd_m, BUS_DMA_READ | BUS_DMA_NOWAIT); | |
1294 | if (error != 0) { | 1294 | if (error != 0) { | |
1295 | panic("%s: could not load old rx mbuf", | 1295 | panic("%s: could not load old rx mbuf", | |
1296 | device_xname(sc->sc_dev)); | 1296 | device_xname(sc->sc_dev)); | |
1297 | } | 1297 | } | |
1298 | ifp->if_ierrors++; | 1298 | if_statinc(ifp, if_ierrors); | |
1299 | goto skip; | 1299 | goto skip; | |
1300 | } | 1300 | } | |
1301 | physaddr = data->rd_map->dm_segs[0].ds_addr; | 1301 | physaddr = data->rd_map->dm_segs[0].ds_addr; | |
1302 | 1302 | |||
1303 | /* | 1303 | /* | |
1304 | * New mbuf loaded, update RX ring and continue | 1304 | * New mbuf loaded, update RX ring and continue | |
1305 | */ | 1305 | */ | |
1306 | m = data->rd_m; | 1306 | m = data->rd_m; | |
1307 | data->rd_m = mnew; | 1307 | data->rd_m = mnew; | |
1308 | desc->ddesc_data = htole32(physaddr); | 1308 | desc->ddesc_data = htole32(physaddr); | |
1309 | 1309 | |||
1310 | /* finalize mbuf */ | 1310 | /* finalize mbuf */ | |
1311 | m->m_pkthdr.len = m->m_len = len; | 1311 | m->m_pkthdr.len = m->m_len = len; | |
1312 | m_set_rcvif(m, ifp); | 1312 | m_set_rcvif(m, ifp); | |
1313 | m->m_flags |= M_HASFCS; | 1313 | m->m_flags |= M_HASFCS; | |
1314 | 1314 | |||
1315 | if_percpuq_enqueue(sc->sc_ipq, m); | 1315 | if_percpuq_enqueue(sc->sc_ipq, m); | |
1316 | 1316 | |||
1317 | skip: | 1317 | skip: | |
1318 | bus_dmamap_sync(sc->sc_dmat, data->rd_map, 0, | 1318 | bus_dmamap_sync(sc->sc_dmat, data->rd_map, 0, | |
1319 | data->rd_map->dm_mapsize, BUS_DMASYNC_PREREAD); | 1319 | data->rd_map->dm_mapsize, BUS_DMASYNC_PREREAD); | |
1320 | 1320 | |||
1321 | sc->sc_descm->rx_init_flags(desc); | 1321 | sc->sc_descm->rx_init_flags(desc); | |
1322 | sc->sc_descm->rx_set_len(desc, data->rd_m->m_len); | 1322 | sc->sc_descm->rx_set_len(desc, data->rd_m->m_len); | |
1323 | sc->sc_descm->rx_set_owned_by_dev(desc); | 1323 | sc->sc_descm->rx_set_owned_by_dev(desc); | |
1324 | 1324 | |||
1325 | bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_ring_map, | 1325 | bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_ring_map, | |
1326 | RX_DESC_OFFSET(i), sizeof(*desc), | 1326 | RX_DESC_OFFSET(i), sizeof(*desc), | |
1327 | BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); | 1327 | BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); | |
1328 | } | 1328 | } | |
1329 | 1329 | |||
1330 | /* update RX pointer */ | 1330 | /* update RX pointer */ | |
1331 | sc->sc_rxq.r_cur = i; | 1331 | sc->sc_rxq.r_cur = i; | |
1332 | 1332 | |||
1333 | mutex_exit(&sc->sc_rxq.r_mtx); | 1333 | mutex_exit(&sc->sc_rxq.r_mtx); | |
1334 | } | 1334 | } | |
1335 | 1335 | |||
1336 | /* | 1336 | /* | |
1337 | * Reverse order of bits - http://aggregate.org/MAGIC/#Bit%20Reversal | 1337 | * Reverse order of bits - http://aggregate.org/MAGIC/#Bit%20Reversal | |
1338 | */ | 1338 | */ | |
1339 | static uint32_t | 1339 | static uint32_t | |
1340 | bitrev32(uint32_t x) | 1340 | bitrev32(uint32_t x) | |
1341 | { | 1341 | { | |
1342 | x = (((x & 0xaaaaaaaa) >> 1) | ((x & 0x55555555) << 1)); | 1342 | x = (((x & 0xaaaaaaaa) >> 1) | ((x & 0x55555555) << 1)); | |
1343 | x = (((x & 0xcccccccc) >> 2) | ((x & 0x33333333) << 2)); | 1343 | x = (((x & 0xcccccccc) >> 2) | ((x & 0x33333333) << 2)); | |
1344 | x = (((x & 0xf0f0f0f0) >> 4) | ((x & 0x0f0f0f0f) << 4)); | 1344 | x = (((x & 0xf0f0f0f0) >> 4) | ((x & 0x0f0f0f0f) << 4)); | |
1345 | x = (((x & 0xff00ff00) >> 8) | ((x & 0x00ff00ff) << 8)); | 1345 | x = (((x & 0xff00ff00) >> 8) | ((x & 0x00ff00ff) << 8)); | |
1346 | 1346 | |||
1347 | return (x >> 16) | (x << 16); | 1347 | return (x >> 16) | (x << 16); | |
1348 | } | 1348 | } | |
1349 | 1349 | |||
1350 | static void | 1350 | static void | |
1351 | dwc_gmac_setmulti(struct dwc_gmac_softc *sc) | 1351 | dwc_gmac_setmulti(struct dwc_gmac_softc *sc) | |
1352 | { | 1352 | { | |
1353 | struct ifnet * const ifp = &sc->sc_ec.ec_if; | 1353 | struct ifnet * const ifp = &sc->sc_ec.ec_if; | |
1354 | struct ether_multi *enm; | 1354 | struct ether_multi *enm; | |
1355 | struct ether_multistep step; | 1355 | struct ether_multistep step; | |
1356 | struct ethercom *ec = &sc->sc_ec; | 1356 | struct ethercom *ec = &sc->sc_ec; | |
1357 | uint32_t hashes[2] = { 0, 0 }; | 1357 | uint32_t hashes[2] = { 0, 0 }; | |
1358 | uint32_t ffilt, h; | 1358 | uint32_t ffilt, h; | |
1359 | int mcnt; | 1359 | int mcnt; | |
1360 | 1360 | |||
1361 | KASSERT(mutex_owned(sc->sc_lock)); | 1361 | KASSERT(mutex_owned(sc->sc_lock)); | |
1362 | 1362 | |||
1363 | ffilt = bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_FFILT); | 1363 | ffilt = bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_FFILT); | |
1364 | 1364 | |||
1365 | if (ifp->if_flags & IFF_PROMISC) { | 1365 | if (ifp->if_flags & IFF_PROMISC) { | |
1366 | ffilt |= AWIN_GMAC_MAC_FFILT_PR; | 1366 | ffilt |= AWIN_GMAC_MAC_FFILT_PR; | |
1367 | goto special_filter; | 1367 | goto special_filter; | |
1368 | } | 1368 | } | |
1369 | 1369 | |||
1370 | ffilt &= ~(AWIN_GMAC_MAC_FFILT_PM | AWIN_GMAC_MAC_FFILT_PR); | 1370 | ffilt &= ~(AWIN_GMAC_MAC_FFILT_PM | AWIN_GMAC_MAC_FFILT_PR); | |
1371 | 1371 | |||
1372 | bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_HTLOW, 0); | 1372 | bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_HTLOW, 0); | |
1373 | bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_HTHIGH, 0); | 1373 | bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_HTHIGH, 0); | |
1374 | 1374 | |||
1375 | ETHER_LOCK(ec); | 1375 | ETHER_LOCK(ec); | |
1376 | ec->ec_flags &= ~ETHER_F_ALLMULTI; | 1376 | ec->ec_flags &= ~ETHER_F_ALLMULTI; | |
1377 | ETHER_FIRST_MULTI(step, ec, enm); | 1377 | ETHER_FIRST_MULTI(step, ec, enm); | |
1378 | mcnt = 0; | 1378 | mcnt = 0; | |
1379 | while (enm != NULL) { | 1379 | while (enm != NULL) { | |
1380 | if (memcmp(enm->enm_addrlo, enm->enm_addrhi, | 1380 | if (memcmp(enm->enm_addrlo, enm->enm_addrhi, | |
1381 | ETHER_ADDR_LEN) != 0) { | 1381 | ETHER_ADDR_LEN) != 0) { | |
1382 | ffilt |= AWIN_GMAC_MAC_FFILT_PM; | 1382 | ffilt |= AWIN_GMAC_MAC_FFILT_PM; | |
1383 | ec->ec_flags |= ETHER_F_ALLMULTI; | 1383 | ec->ec_flags |= ETHER_F_ALLMULTI; | |
1384 | ETHER_UNLOCK(ec); | 1384 | ETHER_UNLOCK(ec); | |
1385 | goto special_filter; | 1385 | goto special_filter; | |
1386 | } | 1386 | } | |
1387 | 1387 | |||
1388 | h = bitrev32( | 1388 | h = bitrev32( | |
1389 | ~ether_crc32_le(enm->enm_addrlo, ETHER_ADDR_LEN) | 1389 | ~ether_crc32_le(enm->enm_addrlo, ETHER_ADDR_LEN) | |
1390 | ) >> 26; | 1390 | ) >> 26; | |
1391 | hashes[h >> 5] |= (1 << (h & 0x1f)); | 1391 | hashes[h >> 5] |= (1 << (h & 0x1f)); | |
1392 | 1392 | |||
1393 | mcnt++; | 1393 | mcnt++; | |
1394 | ETHER_NEXT_MULTI(step, enm); | 1394 | ETHER_NEXT_MULTI(step, enm); | |
1395 | } | 1395 | } | |
1396 | ETHER_UNLOCK(ec); | 1396 | ETHER_UNLOCK(ec); | |
1397 | 1397 | |||
1398 | if (mcnt) | 1398 | if (mcnt) | |
1399 | ffilt |= AWIN_GMAC_MAC_FFILT_HMC; | 1399 | ffilt |= AWIN_GMAC_MAC_FFILT_HMC; | |
1400 | else | 1400 | else | |
1401 | ffilt &= ~AWIN_GMAC_MAC_FFILT_HMC; | 1401 | ffilt &= ~AWIN_GMAC_MAC_FFILT_HMC; | |
1402 | 1402 | |||
1403 | bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_FFILT, ffilt); | 1403 | bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_FFILT, ffilt); | |
1404 | bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_HTLOW, | 1404 | bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_HTLOW, | |
1405 | hashes[0]); | 1405 | hashes[0]); | |
1406 | bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_HTHIGH, | 1406 | bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_HTHIGH, | |
1407 | hashes[1]); | 1407 | hashes[1]); | |
1408 | sc->sc_if_flags = ifp->if_flags; | 1408 | sc->sc_if_flags = ifp->if_flags; | |
1409 | 1409 | |||
1410 | #ifdef DWC_GMAC_DEBUG | 1410 | #ifdef DWC_GMAC_DEBUG | |
1411 | dwc_gmac_dump_ffilt(sc, ffilt); | 1411 | dwc_gmac_dump_ffilt(sc, ffilt); | |
1412 | #endif | 1412 | #endif | |
1413 | return; | 1413 | return; | |
1414 | 1414 | |||
1415 | special_filter: | 1415 | special_filter: | |
1416 | #ifdef DWC_GMAC_DEBUG | 1416 | #ifdef DWC_GMAC_DEBUG | |
1417 | dwc_gmac_dump_ffilt(sc, ffilt); | 1417 | dwc_gmac_dump_ffilt(sc, ffilt); | |
1418 | #endif | 1418 | #endif | |
1419 | /* no MAC hashes, ALLMULTI or PROMISC */ | 1419 | /* no MAC hashes, ALLMULTI or PROMISC */ | |
1420 | bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_FFILT, | 1420 | bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_FFILT, | |
1421 | ffilt); | 1421 | ffilt); | |
1422 | bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_HTLOW, | 1422 | bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_HTLOW, | |
1423 | 0xffffffff); | 1423 | 0xffffffff); | |
1424 | bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_HTHIGH, | 1424 | bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_HTHIGH, | |
1425 | 0xffffffff); | 1425 | 0xffffffff); | |
1426 | sc->sc_if_flags = sc->sc_ec.ec_if.if_flags; | 1426 | sc->sc_if_flags = sc->sc_ec.ec_if.if_flags; | |
1427 | } | 1427 | } | |
1428 | 1428 | |||
1429 | int | 1429 | int | |
1430 | dwc_gmac_intr(struct dwc_gmac_softc *sc) | 1430 | dwc_gmac_intr(struct dwc_gmac_softc *sc) | |
1431 | { | 1431 | { | |
1432 | uint32_t status, dma_status; | 1432 | uint32_t status, dma_status; | |
1433 | int rv = 0; | 1433 | int rv = 0; | |
1434 | 1434 | |||
1435 | if (sc->sc_stopping) | 1435 | if (sc->sc_stopping) | |
1436 | return 0; | 1436 | return 0; | |
1437 | 1437 | |||
1438 | status = bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_INTR); | 1438 | status = bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_INTR); | |
1439 | if (status & AWIN_GMAC_MII_IRQ) { | 1439 | if (status & AWIN_GMAC_MII_IRQ) { | |
1440 | (void)bus_space_read_4(sc->sc_bst, sc->sc_bsh, | 1440 | (void)bus_space_read_4(sc->sc_bst, sc->sc_bsh, | |
1441 | AWIN_GMAC_MII_STATUS); | 1441 | AWIN_GMAC_MII_STATUS); | |
1442 | rv = 1; | 1442 | rv = 1; | |
1443 | mii_pollstat(&sc->sc_mii); | 1443 | mii_pollstat(&sc->sc_mii); | |
1444 | } | 1444 | } | |
1445 | 1445 | |||
1446 | dma_status = bus_space_read_4(sc->sc_bst, sc->sc_bsh, | 1446 | dma_status = bus_space_read_4(sc->sc_bst, sc->sc_bsh, | |
1447 | AWIN_GMAC_DMA_STATUS); | 1447 | AWIN_GMAC_DMA_STATUS); | |
1448 | 1448 | |||
1449 | if (dma_status & (GMAC_DMA_INT_NIE | GMAC_DMA_INT_AIE)) | 1449 | if (dma_status & (GMAC_DMA_INT_NIE | GMAC_DMA_INT_AIE)) | |
1450 | rv = 1; | 1450 | rv = 1; | |
1451 | 1451 | |||
1452 | if (dma_status & GMAC_DMA_INT_TIE) | 1452 | if (dma_status & GMAC_DMA_INT_TIE) | |
1453 | dwc_gmac_tx_intr(sc); | 1453 | dwc_gmac_tx_intr(sc); | |
1454 | 1454 | |||
1455 | if (dma_status & GMAC_DMA_INT_RIE) | 1455 | if (dma_status & GMAC_DMA_INT_RIE) | |
1456 | dwc_gmac_rx_intr(sc); | 1456 | dwc_gmac_rx_intr(sc); | |
1457 | 1457 | |||
1458 | /* | 1458 | /* | |
1459 | * Check error conditions | 1459 | * Check error conditions | |
1460 | */ | 1460 | */ | |
1461 | if (dma_status & GMAC_DMA_INT_ERRORS) { | 1461 | if (dma_status & GMAC_DMA_INT_ERRORS) { | |
1462 | sc->sc_ec.ec_if.if_oerrors++; | 1462 | if_statinc(&sc->sc_ec.ec_if, if_oerrors); | |
1463 | #ifdef DWC_GMAC_DEBUG | 1463 | #ifdef DWC_GMAC_DEBUG | |
1464 | dwc_dump_and_abort(sc, "interrupt error condition"); | 1464 | dwc_dump_and_abort(sc, "interrupt error condition"); | |
1465 | #endif | 1465 | #endif | |
1466 | } | 1466 | } | |
1467 | 1467 | |||
1468 | rnd_add_uint32(&sc->rnd_source, dma_status); | 1468 | rnd_add_uint32(&sc->rnd_source, dma_status); | |
1469 | 1469 | |||
1470 | /* ack interrupt */ | 1470 | /* ack interrupt */ | |
1471 | if (dma_status) | 1471 | if (dma_status) | |
1472 | bus_space_write_4(sc->sc_bst, sc->sc_bsh, | 1472 | bus_space_write_4(sc->sc_bst, sc->sc_bsh, | |
1473 | AWIN_GMAC_DMA_STATUS, dma_status & GMAC_DMA_INT_MASK); | 1473 | AWIN_GMAC_DMA_STATUS, dma_status & GMAC_DMA_INT_MASK); | |
1474 | 1474 | |||
1475 | /* | 1475 | /* | |
1476 | * Get more packets | 1476 | * Get more packets | |
1477 | */ | 1477 | */ | |
1478 | if (rv) | 1478 | if (rv) | |
1479 | if_schedule_deferred_start(&sc->sc_ec.ec_if); | 1479 | if_schedule_deferred_start(&sc->sc_ec.ec_if); | |
1480 | 1480 | |||
1481 | return rv; | 1481 | return rv; | |
1482 | } | 1482 | } | |
1483 | 1483 | |||
1484 | static void | 1484 | static void | |
1485 | dwc_gmac_desc_set_owned_by_dev(struct dwc_gmac_dev_dmadesc *desc) | 1485 | dwc_gmac_desc_set_owned_by_dev(struct dwc_gmac_dev_dmadesc *desc) | |
1486 | { | 1486 | { | |
1487 | 1487 | |||
1488 | desc->ddesc_status0 |= htole32(DDESC_STATUS_OWNEDBYDEV); | 1488 | desc->ddesc_status0 |= htole32(DDESC_STATUS_OWNEDBYDEV); | |
1489 | } | 1489 | } | |
1490 | 1490 | |||
1491 | static int | 1491 | static int | |
1492 | dwc_gmac_desc_is_owned_by_dev(struct dwc_gmac_dev_dmadesc *desc) | 1492 | dwc_gmac_desc_is_owned_by_dev(struct dwc_gmac_dev_dmadesc *desc) | |
1493 | { | 1493 | { | |
1494 | 1494 | |||
1495 | return !!(le32toh(desc->ddesc_status0) & DDESC_STATUS_OWNEDBYDEV); | 1495 | return !!(le32toh(desc->ddesc_status0) & DDESC_STATUS_OWNEDBYDEV); | |
1496 | } | 1496 | } | |
1497 | 1497 | |||
1498 | static void | 1498 | static void | |
1499 | dwc_gmac_desc_std_set_len(struct dwc_gmac_dev_dmadesc *desc, int len) | 1499 | dwc_gmac_desc_std_set_len(struct dwc_gmac_dev_dmadesc *desc, int len) | |
1500 | { | 1500 | { | |
1501 | uint32_t cntl = le32toh(desc->ddesc_cntl1); | 1501 | uint32_t cntl = le32toh(desc->ddesc_cntl1); | |
1502 | 1502 | |||
1503 | desc->ddesc_cntl1 = htole32((cntl & ~DDESC_CNTL_SIZE1MASK) | | 1503 | desc->ddesc_cntl1 = htole32((cntl & ~DDESC_CNTL_SIZE1MASK) | | |
1504 | __SHIFTIN(len, DDESC_CNTL_SIZE1MASK)); | 1504 | __SHIFTIN(len, DDESC_CNTL_SIZE1MASK)); | |
1505 | } | 1505 | } | |
1506 | 1506 | |||
1507 | static uint32_t | 1507 | static uint32_t | |
1508 | dwc_gmac_desc_std_get_len(struct dwc_gmac_dev_dmadesc *desc) | 1508 | dwc_gmac_desc_std_get_len(struct dwc_gmac_dev_dmadesc *desc) | |
1509 | { | 1509 | { | |
1510 | 1510 | |||
1511 | return __SHIFTOUT(le32toh(desc->ddesc_status0), DDESC_STATUS_FRMLENMSK); | 1511 | return __SHIFTOUT(le32toh(desc->ddesc_status0), DDESC_STATUS_FRMLENMSK); | |
1512 | } | 1512 | } | |
1513 | 1513 | |||
1514 | static void | 1514 | static void | |
1515 | dwc_gmac_desc_std_tx_init_flags(struct dwc_gmac_dev_dmadesc *desc) | 1515 | dwc_gmac_desc_std_tx_init_flags(struct dwc_gmac_dev_dmadesc *desc) | |
1516 | { | 1516 | { | |
1517 | 1517 | |||
1518 | desc->ddesc_status0 = 0; | 1518 | desc->ddesc_status0 = 0; | |
1519 | desc->ddesc_cntl1 = htole32(DDESC_CNTL_TXCHAIN); | 1519 | desc->ddesc_cntl1 = htole32(DDESC_CNTL_TXCHAIN); | |
1520 | } | 1520 | } | |
1521 | 1521 | |||
1522 | static void | 1522 | static void | |
1523 | dwc_gmac_desc_std_tx_set_first_frag(struct dwc_gmac_dev_dmadesc *desc) | 1523 | dwc_gmac_desc_std_tx_set_first_frag(struct dwc_gmac_dev_dmadesc *desc) | |
1524 | { | 1524 | { | |
1525 | uint32_t cntl = le32toh(desc->ddesc_cntl1); | 1525 | uint32_t cntl = le32toh(desc->ddesc_cntl1); | |
1526 | 1526 | |||
1527 | desc->ddesc_cntl1 = htole32(cntl | DDESC_CNTL_TXFIRST); | 1527 | desc->ddesc_cntl1 = htole32(cntl | DDESC_CNTL_TXFIRST); | |
1528 | } | 1528 | } | |
1529 | 1529 | |||
1530 | static void | 1530 | static void | |
1531 | dwc_gmac_desc_std_tx_set_last_frag(struct dwc_gmac_dev_dmadesc *desc) | 1531 | dwc_gmac_desc_std_tx_set_last_frag(struct dwc_gmac_dev_dmadesc *desc) | |
1532 | { | 1532 | { | |
1533 | uint32_t cntl = le32toh(desc->ddesc_cntl1); | 1533 | uint32_t cntl = le32toh(desc->ddesc_cntl1); | |
1534 | 1534 | |||
1535 | desc->ddesc_cntl1 = htole32(cntl | | 1535 | desc->ddesc_cntl1 = htole32(cntl | | |
1536 | DDESC_CNTL_TXLAST | DDESC_CNTL_TXINT); | 1536 | DDESC_CNTL_TXLAST | DDESC_CNTL_TXINT); | |
1537 | } | 1537 | } | |
1538 | 1538 | |||
1539 | static void | 1539 | static void | |
1540 | dwc_gmac_desc_std_rx_init_flags(struct dwc_gmac_dev_dmadesc *desc) | 1540 | dwc_gmac_desc_std_rx_init_flags(struct dwc_gmac_dev_dmadesc *desc) | |
1541 | { | 1541 | { | |
1542 | 1542 | |||
1543 | desc->ddesc_status0 = 0; | 1543 | desc->ddesc_status0 = 0; | |
1544 | desc->ddesc_cntl1 = htole32(DDESC_CNTL_TXCHAIN); | 1544 | desc->ddesc_cntl1 = htole32(DDESC_CNTL_TXCHAIN); | |
1545 | } | 1545 | } | |
1546 | 1546 | |||
1547 | static int | 1547 | static int | |
1548 | dwc_gmac_desc_std_rx_has_error(struct dwc_gmac_dev_dmadesc *desc) { | 1548 | dwc_gmac_desc_std_rx_has_error(struct dwc_gmac_dev_dmadesc *desc) { | |
1549 | return !!(le32toh(desc->ddesc_status0) & | 1549 | return !!(le32toh(desc->ddesc_status0) & | |
1550 | (DDESC_STATUS_RXERROR | DDESC_STATUS_RXTRUNCATED)); | 1550 | (DDESC_STATUS_RXERROR | DDESC_STATUS_RXTRUNCATED)); | |
1551 | } | 1551 | } | |
1552 | 1552 | |||
1553 | static void | 1553 | static void | |
1554 | dwc_gmac_desc_enh_set_len(struct dwc_gmac_dev_dmadesc *desc, int len) | 1554 | dwc_gmac_desc_enh_set_len(struct dwc_gmac_dev_dmadesc *desc, int len) | |
1555 | { | 1555 | { | |
1556 | uint32_t tdes1 = le32toh(desc->ddesc_cntl1); | 1556 | uint32_t tdes1 = le32toh(desc->ddesc_cntl1); | |
1557 | 1557 | |||
1558 | desc->ddesc_cntl1 = htole32((tdes1 & ~DDESC_DES1_SIZE1MASK) | | 1558 | desc->ddesc_cntl1 = htole32((tdes1 & ~DDESC_DES1_SIZE1MASK) | | |
1559 | __SHIFTIN(len, DDESC_DES1_SIZE1MASK)); | 1559 | __SHIFTIN(len, DDESC_DES1_SIZE1MASK)); | |
1560 | } | 1560 | } | |
1561 | 1561 | |||
1562 | static uint32_t | 1562 | static uint32_t | |
1563 | dwc_gmac_desc_enh_get_len(struct dwc_gmac_dev_dmadesc *desc) | 1563 | dwc_gmac_desc_enh_get_len(struct dwc_gmac_dev_dmadesc *desc) | |
1564 | { | 1564 | { | |
1565 | 1565 | |||
1566 | return __SHIFTOUT(le32toh(desc->ddesc_status0), DDESC_RDES0_FL); | 1566 | return __SHIFTOUT(le32toh(desc->ddesc_status0), DDESC_RDES0_FL); | |
1567 | } | 1567 | } | |
1568 | 1568 | |||
1569 | static void | 1569 | static void | |
1570 | dwc_gmac_desc_enh_tx_init_flags(struct dwc_gmac_dev_dmadesc *desc) | 1570 | dwc_gmac_desc_enh_tx_init_flags(struct dwc_gmac_dev_dmadesc *desc) | |
1571 | { | 1571 | { | |
1572 | 1572 | |||
1573 | desc->ddesc_status0 = htole32(DDESC_TDES0_TCH); | 1573 | desc->ddesc_status0 = htole32(DDESC_TDES0_TCH); | |
1574 | desc->ddesc_cntl1 = 0; | 1574 | desc->ddesc_cntl1 = 0; | |
1575 | } | 1575 | } | |
1576 | 1576 | |||
1577 | static void | 1577 | static void | |
1578 | dwc_gmac_desc_enh_tx_set_first_frag(struct dwc_gmac_dev_dmadesc *desc) | 1578 | dwc_gmac_desc_enh_tx_set_first_frag(struct dwc_gmac_dev_dmadesc *desc) | |
1579 | { | 1579 | { | |
1580 | uint32_t tdes0 = le32toh(desc->ddesc_status0); | 1580 | uint32_t tdes0 = le32toh(desc->ddesc_status0); | |
1581 | 1581 | |||
1582 | desc->ddesc_status0 = htole32(tdes0 | DDESC_TDES0_FS); | 1582 | desc->ddesc_status0 = htole32(tdes0 | DDESC_TDES0_FS); | |
1583 | } | 1583 | } | |
1584 | 1584 | |||
1585 | static void | 1585 | static void | |
1586 | dwc_gmac_desc_enh_tx_set_last_frag(struct dwc_gmac_dev_dmadesc *desc) | 1586 | dwc_gmac_desc_enh_tx_set_last_frag(struct dwc_gmac_dev_dmadesc *desc) | |
1587 | { | 1587 | { | |
1588 | uint32_t tdes0 = le32toh(desc->ddesc_status0); | 1588 | uint32_t tdes0 = le32toh(desc->ddesc_status0); | |
1589 | 1589 | |||
1590 | desc->ddesc_status0 = htole32(tdes0 | DDESC_TDES0_LS | DDESC_TDES0_IC); | 1590 | desc->ddesc_status0 = htole32(tdes0 | DDESC_TDES0_LS | DDESC_TDES0_IC); | |
1591 | } | 1591 | } | |
1592 | 1592 | |||
1593 | static void | 1593 | static void | |
1594 | dwc_gmac_desc_enh_rx_init_flags(struct dwc_gmac_dev_dmadesc *desc) | 1594 | dwc_gmac_desc_enh_rx_init_flags(struct dwc_gmac_dev_dmadesc *desc) | |
1595 | { | 1595 | { | |
1596 | 1596 | |||
1597 | desc->ddesc_status0 = 0; | 1597 | desc->ddesc_status0 = 0; | |
1598 | desc->ddesc_cntl1 = htole32(DDESC_RDES1_RCH); | 1598 | desc->ddesc_cntl1 = htole32(DDESC_RDES1_RCH); | |
1599 | } | 1599 | } | |
1600 | 1600 | |||
1601 | static int | 1601 | static int | |
1602 | dwc_gmac_desc_enh_rx_has_error(struct dwc_gmac_dev_dmadesc *desc) | 1602 | dwc_gmac_desc_enh_rx_has_error(struct dwc_gmac_dev_dmadesc *desc) | |
1603 | { | 1603 | { | |
1604 | 1604 | |||
1605 | return !!(le32toh(desc->ddesc_status0) & | 1605 | return !!(le32toh(desc->ddesc_status0) & | |
1606 | (DDESC_RDES0_ES | DDESC_RDES0_LE)); | 1606 | (DDESC_RDES0_ES | DDESC_RDES0_LE)); | |
1607 | } | 1607 | } | |
1608 | 1608 | |||
1609 | #ifdef DWC_GMAC_DEBUG | 1609 | #ifdef DWC_GMAC_DEBUG | |
1610 | static void | 1610 | static void | |
1611 | dwc_gmac_dump_dma(struct dwc_gmac_softc *sc) | 1611 | dwc_gmac_dump_dma(struct dwc_gmac_softc *sc) | |
1612 | { | 1612 | { | |
1613 | aprint_normal_dev(sc->sc_dev, "busmode: %08x\n", | 1613 | aprint_normal_dev(sc->sc_dev, "busmode: %08x\n", | |
1614 | bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_BUSMODE)); | 1614 | bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_BUSMODE)); | |
1615 | aprint_normal_dev(sc->sc_dev, "tx poll: %08x\n", | 1615 | aprint_normal_dev(sc->sc_dev, "tx poll: %08x\n", | |
1616 | bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_TXPOLL)); | 1616 | bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_TXPOLL)); | |
1617 | aprint_normal_dev(sc->sc_dev, "rx poll: %08x\n", | 1617 | aprint_normal_dev(sc->sc_dev, "rx poll: %08x\n", | |
1618 | bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_RXPOLL)); | 1618 | bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_RXPOLL)); | |
1619 | aprint_normal_dev(sc->sc_dev, "rx descriptors: %08x\n", | 1619 | aprint_normal_dev(sc->sc_dev, "rx descriptors: %08x\n", | |
1620 | bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_RX_ADDR)); | 1620 | bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_RX_ADDR)); | |
1621 | aprint_normal_dev(sc->sc_dev, "tx descriptors: %08x\n", | 1621 | aprint_normal_dev(sc->sc_dev, "tx descriptors: %08x\n", | |
1622 | bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_TX_ADDR)); | 1622 | bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_TX_ADDR)); | |
1623 | aprint_normal_dev(sc->sc_dev, "status: %08x\n", | 1623 | aprint_normal_dev(sc->sc_dev, "status: %08x\n", | |
1624 | bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_STATUS)); | 1624 | bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_STATUS)); | |
1625 | aprint_normal_dev(sc->sc_dev, "op mode: %08x\n", | 1625 | aprint_normal_dev(sc->sc_dev, "op mode: %08x\n", | |
1626 | bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_OPMODE)); | 1626 | bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_OPMODE)); | |
1627 | aprint_normal_dev(sc->sc_dev, "int enable: %08x\n", | 1627 | aprint_normal_dev(sc->sc_dev, "int enable: %08x\n", | |
1628 | bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_INTENABLE)); | 1628 | bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_INTENABLE)); | |
1629 | aprint_normal_dev(sc->sc_dev, "cur tx: %08x\n", | 1629 | aprint_normal_dev(sc->sc_dev, "cur tx: %08x\n", | |
1630 | bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_CUR_TX_DESC)); | 1630 | bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_CUR_TX_DESC)); | |
1631 | aprint_normal_dev(sc->sc_dev, "cur rx: %08x\n", | 1631 | aprint_normal_dev(sc->sc_dev, "cur rx: %08x\n", | |
1632 | bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_CUR_RX_DESC)); | 1632 | bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_CUR_RX_DESC)); | |
1633 | aprint_normal_dev(sc->sc_dev, "cur tx buffer: %08x\n", | 1633 | aprint_normal_dev(sc->sc_dev, "cur tx buffer: %08x\n", | |
1634 | bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_CUR_TX_BUFADDR)); | 1634 | bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_CUR_TX_BUFADDR)); | |
1635 | aprint_normal_dev(sc->sc_dev, "cur rx buffer: %08x\n", | 1635 | aprint_normal_dev(sc->sc_dev, "cur rx buffer: %08x\n", | |
1636 | bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_CUR_RX_BUFADDR)); | 1636 | bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_CUR_RX_BUFADDR)); | |
1637 | } | 1637 | } | |
1638 | 1638 | |||
1639 | static void | 1639 | static void | |
1640 | dwc_gmac_dump_tx_desc(struct dwc_gmac_softc *sc) | 1640 | dwc_gmac_dump_tx_desc(struct dwc_gmac_softc *sc) | |
1641 | { | 1641 | { | |
1642 | int i; | 1642 | int i; | |
1643 | 1643 | |||
1644 | aprint_normal_dev(sc->sc_dev, "TX queue: cur=%d, next=%d, queued=%d\n", | 1644 | aprint_normal_dev(sc->sc_dev, "TX queue: cur=%d, next=%d, queued=%d\n", | |
1645 | sc->sc_txq.t_cur, sc->sc_txq.t_next, sc->sc_txq.t_queued); | 1645 | sc->sc_txq.t_cur, sc->sc_txq.t_next, sc->sc_txq.t_queued); | |
1646 | aprint_normal_dev(sc->sc_dev, "TX DMA descriptors:\n"); | 1646 | aprint_normal_dev(sc->sc_dev, "TX DMA descriptors:\n"); | |
1647 | for (i = 0; i < AWGE_TX_RING_COUNT; i++) { | 1647 | for (i = 0; i < AWGE_TX_RING_COUNT; i++) { | |
1648 | struct dwc_gmac_dev_dmadesc *desc = &sc->sc_txq.t_desc[i]; | 1648 | struct dwc_gmac_dev_dmadesc *desc = &sc->sc_txq.t_desc[i]; | |
1649 | aprint_normal("#%d (%08lx): status: %08x cntl: %08x " | 1649 | aprint_normal("#%d (%08lx): status: %08x cntl: %08x " | |
1650 | "data: %08x next: %08x\n", | 1650 | "data: %08x next: %08x\n", | |
1651 | i, sc->sc_txq.t_physaddr + | 1651 | i, sc->sc_txq.t_physaddr + | |
1652 | i*sizeof(struct dwc_gmac_dev_dmadesc), | 1652 | i*sizeof(struct dwc_gmac_dev_dmadesc), | |
1653 | le32toh(desc->ddesc_status0), le32toh(desc->ddesc_cntl1), | 1653 | le32toh(desc->ddesc_status0), le32toh(desc->ddesc_cntl1), | |
1654 | le32toh(desc->ddesc_data), le32toh(desc->ddesc_next)); | 1654 | le32toh(desc->ddesc_data), le32toh(desc->ddesc_next)); | |
1655 | } | 1655 | } | |
1656 | } | 1656 | } | |
1657 | 1657 | |||
1658 | static void | 1658 | static void | |
1659 | dwc_gmac_dump_rx_desc(struct dwc_gmac_softc *sc) | 1659 | dwc_gmac_dump_rx_desc(struct dwc_gmac_softc *sc) | |
1660 | { | 1660 | { | |
1661 | int i; | 1661 | int i; | |
1662 | 1662 | |||
1663 | aprint_normal_dev(sc->sc_dev, "RX queue: cur=%d, next=%d\n", | 1663 | aprint_normal_dev(sc->sc_dev, "RX queue: cur=%d, next=%d\n", | |
1664 | sc->sc_rxq.r_cur, sc->sc_rxq.r_next); | 1664 | sc->sc_rxq.r_cur, sc->sc_rxq.r_next); | |
1665 | aprint_normal_dev(sc->sc_dev, "RX DMA descriptors:\n"); | 1665 | aprint_normal_dev(sc->sc_dev, "RX DMA descriptors:\n"); | |
1666 | for (i = 0; i < AWGE_RX_RING_COUNT; i++) { | 1666 | for (i = 0; i < AWGE_RX_RING_COUNT; i++) { | |
1667 | struct dwc_gmac_dev_dmadesc *desc = &sc->sc_rxq.r_desc[i]; | 1667 | struct dwc_gmac_dev_dmadesc *desc = &sc->sc_rxq.r_desc[i]; | |
1668 | aprint_normal("#%d (%08lx): status: %08x cntl: %08x " | 1668 | aprint_normal("#%d (%08lx): status: %08x cntl: %08x " | |
1669 | "data: %08x next: %08x\n", | 1669 | "data: %08x next: %08x\n", | |
1670 | i, sc->sc_rxq.r_physaddr + | 1670 | i, sc->sc_rxq.r_physaddr + | |
1671 | i*sizeof(struct dwc_gmac_dev_dmadesc), | 1671 | i*sizeof(struct dwc_gmac_dev_dmadesc), | |
1672 | le32toh(desc->ddesc_status0), le32toh(desc->ddesc_cntl1), | 1672 | le32toh(desc->ddesc_status0), le32toh(desc->ddesc_cntl1), | |
1673 | le32toh(desc->ddesc_data), le32toh(desc->ddesc_next)); | 1673 | le32toh(desc->ddesc_data), le32toh(desc->ddesc_next)); | |
1674 | } | 1674 | } | |
1675 | } | 1675 | } | |
1676 | 1676 | |||
1677 | static void | 1677 | static void | |
1678 | dwc_dump_status(struct dwc_gmac_softc *sc) | 1678 | dwc_dump_status(struct dwc_gmac_softc *sc) | |
1679 | { | 1679 | { | |
1680 | uint32_t status = bus_space_read_4(sc->sc_bst, sc->sc_bsh, | 1680 | uint32_t status = bus_space_read_4(sc->sc_bst, sc->sc_bsh, | |
1681 | AWIN_GMAC_MAC_INTR); | 1681 | AWIN_GMAC_MAC_INTR); | |
1682 | uint32_t dma_status = bus_space_read_4(sc->sc_bst, sc->sc_bsh, | 1682 | uint32_t dma_status = bus_space_read_4(sc->sc_bst, sc->sc_bsh, | |
1683 | AWIN_GMAC_DMA_STATUS); | 1683 | AWIN_GMAC_DMA_STATUS); | |
1684 | char buf[200]; | 1684 | char buf[200]; | |
1685 | 1685 | |||
1686 | /* print interrupt state */ | 1686 | /* print interrupt state */ | |
1687 | snprintb(buf, sizeof(buf), "\177\20" | 1687 | snprintb(buf, sizeof(buf), "\177\20" | |
1688 | "b\x10""NI\0" | 1688 | "b\x10""NI\0" | |
1689 | "b\x0f""AI\0" | 1689 | "b\x0f""AI\0" | |
1690 | "b\x0e""ER\0" | 1690 | "b\x0e""ER\0" | |
1691 | "b\x0d""FB\0" | 1691 | "b\x0d""FB\0" | |
1692 | "b\x0a""ET\0" | 1692 | "b\x0a""ET\0" | |
1693 | "b\x09""RW\0" | 1693 | "b\x09""RW\0" | |
1694 | "b\x08""RS\0" | 1694 | "b\x08""RS\0" | |
1695 | "b\x07""RU\0" | 1695 | "b\x07""RU\0" | |
1696 | "b\x06""RI\0" | 1696 | "b\x06""RI\0" | |
1697 | "b\x05""UN\0" | 1697 | "b\x05""UN\0" | |
1698 | "b\x04""OV\0" | 1698 | "b\x04""OV\0" | |
1699 | "b\x03""TJ\0" | 1699 | "b\x03""TJ\0" | |
1700 | "b\x02""TU\0" | 1700 | "b\x02""TU\0" | |
1701 | "b\x01""TS\0" | 1701 | "b\x01""TS\0" | |
1702 | "b\x00""TI\0" | 1702 | "b\x00""TI\0" | |
1703 | "\0", dma_status); | 1703 | "\0", dma_status); | |
1704 | aprint_normal_dev(sc->sc_dev, "INTR status: %08x, DMA status: %s\n", | 1704 | aprint_normal_dev(sc->sc_dev, "INTR status: %08x, DMA status: %s\n", | |
1705 | status, buf); | 1705 | status, buf); | |
1706 | } | 1706 | } | |
1707 | 1707 | |||
1708 | static void | 1708 | static void | |
1709 | dwc_dump_and_abort(struct dwc_gmac_softc *sc, const char *msg) | 1709 | dwc_dump_and_abort(struct dwc_gmac_softc *sc, const char *msg) | |
1710 | { | 1710 | { | |
1711 | dwc_dump_status(sc); | 1711 | dwc_dump_status(sc); | |
1712 | dwc_gmac_dump_ffilt(sc, | 1712 | dwc_gmac_dump_ffilt(sc, | |
1713 | bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_FFILT)); | 1713 | bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_FFILT)); | |
1714 | dwc_gmac_dump_dma(sc); | 1714 | dwc_gmac_dump_dma(sc); | |
1715 | dwc_gmac_dump_tx_desc(sc); | 1715 | dwc_gmac_dump_tx_desc(sc); | |
1716 | dwc_gmac_dump_rx_desc(sc); | 1716 | dwc_gmac_dump_rx_desc(sc); | |
1717 | 1717 | |||
1718 | panic("%s", msg); | 1718 | panic("%s", msg); | |
1719 | } | 1719 | } | |
1720 | 1720 | |||
1721 | static void dwc_gmac_dump_ffilt(struct dwc_gmac_softc *sc, uint32_t ffilt) | 1721 | static void dwc_gmac_dump_ffilt(struct dwc_gmac_softc *sc, uint32_t ffilt) | |
1722 | { | 1722 | { | |
1723 | char buf[200]; | 1723 | char buf[200]; | |
1724 | 1724 | |||
1725 | /* print filter setup */ | 1725 | /* print filter setup */ | |
1726 | snprintb(buf, sizeof(buf), "\177\20" | 1726 | snprintb(buf, sizeof(buf), "\177\20" | |
1727 | "b\x1f""RA\0" | 1727 | "b\x1f""RA\0" | |
1728 | "b\x0a""HPF\0" | 1728 | "b\x0a""HPF\0" | |
1729 | "b\x09""SAF\0" | 1729 | "b\x09""SAF\0" | |
1730 | "b\x08""SAIF\0" | 1730 | "b\x08""SAIF\0" | |
1731 | "b\x05""DBF\0" | 1731 | "b\x05""DBF\0" | |
1732 | "b\x04""PM\0" | 1732 | "b\x04""PM\0" | |
1733 | "b\x03""DAIF\0" | 1733 | "b\x03""DAIF\0" | |
1734 | "b\x02""HMC\0" | 1734 | "b\x02""HMC\0" | |
1735 | "b\x01""HUC\0" | 1735 | "b\x01""HUC\0" | |
1736 | "b\x00""PR\0" | 1736 | "b\x00""PR\0" | |
1737 | "\0", ffilt); | 1737 | "\0", ffilt); | |
1738 | aprint_normal_dev(sc->sc_dev, "FFILT: %s\n", buf); | 1738 | aprint_normal_dev(sc->sc_dev, "FFILT: %s\n", buf); | |
1739 | } | 1739 | } | |
1740 | #endif | 1740 | #endif |