| @@ -1,1079 +1,1084 @@ | | | @@ -1,1079 +1,1084 @@ |
1 | /* $NetBSD: if_cemac.c,v 1.21 2019/05/28 07:41:48 msaitoh Exp $ */ | | 1 | /* $NetBSD: if_cemac.c,v 1.22 2020/01/29 05:54:29 thorpej Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 2015 Genetec Corporation. All rights reserved. | | 4 | * Copyright (c) 2015 Genetec Corporation. All rights reserved. |
5 | * Written by Hashimoto Kenichi for Genetec Corporation. | | 5 | * Written by Hashimoto Kenichi for Genetec Corporation. |
6 | * | | 6 | * |
7 | * Based on arch/arm/at91/at91emac.c | | 7 | * Based on arch/arm/at91/at91emac.c |
8 | * | | 8 | * |
9 | * Copyright (c) 2007 Embedtronics Oy | | 9 | * Copyright (c) 2007 Embedtronics Oy |
10 | * All rights reserved. | | 10 | * All rights reserved. |
11 | * | | 11 | * |
12 | * Copyright (c) 2004 Jesse Off | | 12 | * Copyright (c) 2004 Jesse Off |
13 | * All rights reserved. | | 13 | * All rights reserved. |
14 | * | | 14 | * |
15 | * Redistribution and use in source and binary forms, with or without | | 15 | * Redistribution and use in source and binary forms, with or without |
16 | * modification, are permitted provided that the following conditions | | 16 | * modification, are permitted provided that the following conditions |
17 | * are met: | | 17 | * are met: |
18 | * 1. Redistributions of source code must retain the above copyright | | 18 | * 1. Redistributions of source code must retain the above copyright |
19 | * notice, this list of conditions and the following disclaimer. | | 19 | * notice, this list of conditions and the following disclaimer. |
20 | * 2. Redistributions in binary form must reproduce the above copyright | | 20 | * 2. Redistributions in binary form must reproduce the above copyright |
21 | * notice, this list of conditions and the following disclaimer in the | | 21 | * notice, this list of conditions and the following disclaimer in the |
22 | * documentation and/or other materials provided with the distribution. | | 22 | * documentation and/or other materials provided with the distribution. |
23 | * | | 23 | * |
24 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | | 24 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
25 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | | 25 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
26 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | | 26 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
27 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | | 27 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
28 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | | 28 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
29 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | 29 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
30 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | 30 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
31 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | 31 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
32 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | 32 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
33 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | | 33 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
34 | * POSSIBILITY OF SUCH DAMAGE. | | 34 | * POSSIBILITY OF SUCH DAMAGE. |
35 | */ | | 35 | */ |
36 | | | 36 | |
37 | /* | | 37 | /* |
38 | * Cadence EMAC/GEM ethernet controller IP driver | | 38 | * Cadence EMAC/GEM ethernet controller IP driver |
39 | * used by arm/at91, arm/zynq SoC | | 39 | * used by arm/at91, arm/zynq SoC |
40 | */ | | 40 | */ |
41 | | | 41 | |
42 | #include <sys/cdefs.h> | | 42 | #include <sys/cdefs.h> |
43 | __KERNEL_RCSID(0, "$NetBSD: if_cemac.c,v 1.21 2019/05/28 07:41:48 msaitoh Exp $"); | | 43 | __KERNEL_RCSID(0, "$NetBSD: if_cemac.c,v 1.22 2020/01/29 05:54:29 thorpej Exp $"); |
44 | | | 44 | |
45 | #include <sys/types.h> | | 45 | #include <sys/types.h> |
46 | #include <sys/param.h> | | 46 | #include <sys/param.h> |
47 | #include <sys/systm.h> | | 47 | #include <sys/systm.h> |
48 | #include <sys/ioctl.h> | | 48 | #include <sys/ioctl.h> |
49 | #include <sys/kernel.h> | | 49 | #include <sys/kernel.h> |
50 | #include <sys/proc.h> | | 50 | #include <sys/proc.h> |
51 | #include <sys/malloc.h> | | 51 | #include <sys/malloc.h> |
52 | #include <sys/time.h> | | 52 | #include <sys/time.h> |
53 | #include <sys/device.h> | | 53 | #include <sys/device.h> |
54 | #include <uvm/uvm_extern.h> | | 54 | #include <uvm/uvm_extern.h> |
55 | | | 55 | |
56 | #include <sys/bus.h> | | 56 | #include <sys/bus.h> |
57 | #include <machine/intr.h> | | 57 | #include <machine/intr.h> |
58 | | | 58 | |
59 | #include <arm/cpufunc.h> | | 59 | #include <arm/cpufunc.h> |
60 | | | 60 | |
61 | #include <net/if.h> | | 61 | #include <net/if.h> |
62 | #include <net/if_dl.h> | | 62 | #include <net/if_dl.h> |
63 | #include <net/if_types.h> | | 63 | #include <net/if_types.h> |
64 | #include <net/if_media.h> | | 64 | #include <net/if_media.h> |
65 | #include <net/if_ether.h> | | 65 | #include <net/if_ether.h> |
66 | #include <net/bpf.h> | | 66 | #include <net/bpf.h> |
67 | | | 67 | |
68 | #include <dev/mii/mii.h> | | 68 | #include <dev/mii/mii.h> |
69 | #include <dev/mii/miivar.h> | | 69 | #include <dev/mii/miivar.h> |
70 | | | 70 | |
71 | #ifdef INET | | 71 | #ifdef INET |
72 | #include <netinet/in.h> | | 72 | #include <netinet/in.h> |
73 | #include <netinet/in_systm.h> | | 73 | #include <netinet/in_systm.h> |
74 | #include <netinet/in_var.h> | | 74 | #include <netinet/in_var.h> |
75 | #include <netinet/ip.h> | | 75 | #include <netinet/ip.h> |
76 | #include <netinet/if_inarp.h> | | 76 | #include <netinet/if_inarp.h> |
77 | #endif | | 77 | #endif |
78 | | | 78 | |
79 | #include <dev/cadence/cemacreg.h> | | 79 | #include <dev/cadence/cemacreg.h> |
80 | #include <dev/cadence/if_cemacvar.h> | | 80 | #include <dev/cadence/if_cemacvar.h> |
81 | | | 81 | |
82 | #define DEFAULT_MDCDIV 32 | | 82 | #define DEFAULT_MDCDIV 32 |
83 | | | 83 | |
84 | #define CEMAC_READ(x) \ | | 84 | #define CEMAC_READ(x) \ |
85 | bus_space_read_4(sc->sc_iot, sc->sc_ioh, (x)) | | 85 | bus_space_read_4(sc->sc_iot, sc->sc_ioh, (x)) |
86 | #define CEMAC_WRITE(x, y) \ | | 86 | #define CEMAC_WRITE(x, y) \ |
87 | bus_space_write_4(sc->sc_iot, sc->sc_ioh, (x), (y)) | | 87 | bus_space_write_4(sc->sc_iot, sc->sc_ioh, (x), (y)) |
88 | #define CEMAC_GEM_WRITE(x, y) \ | | 88 | #define CEMAC_GEM_WRITE(x, y) \ |
89 | do { \ | | 89 | do { \ |
90 | if (ISSET(sc->cemac_flags, CEMAC_FLAG_GEM)) \ | | 90 | if (ISSET(sc->cemac_flags, CEMAC_FLAG_GEM)) \ |
91 | bus_space_write_4(sc->sc_iot, sc->sc_ioh, (GEM_##x), (y)); \ | | 91 | bus_space_write_4(sc->sc_iot, sc->sc_ioh, (GEM_##x), (y)); \ |
92 | else \ | | 92 | else \ |
93 | bus_space_write_4(sc->sc_iot, sc->sc_ioh, (ETH_##x), (y)); \ | | 93 | bus_space_write_4(sc->sc_iot, sc->sc_ioh, (ETH_##x), (y)); \ |
94 | } while(0) | | 94 | } while(0) |
95 | | | 95 | |
96 | #define RX_QLEN 64 | | 96 | #define RX_QLEN 64 |
97 | #define TX_QLEN 2 /* I'm very sorry but that's where we can get */ | | 97 | #define TX_QLEN 2 /* I'm very sorry but that's where we can get */ |
98 | | | 98 | |
99 | struct cemac_qmeta { | | 99 | struct cemac_qmeta { |
100 | struct mbuf *m; | | 100 | struct mbuf *m; |
101 | bus_dmamap_t m_dmamap; | | 101 | bus_dmamap_t m_dmamap; |
102 | }; | | 102 | }; |
103 | | | 103 | |
104 | struct cemac_softc { | | 104 | struct cemac_softc { |
105 | device_t sc_dev; | | 105 | device_t sc_dev; |
106 | bus_space_tag_t sc_iot; | | 106 | bus_space_tag_t sc_iot; |
107 | bus_space_handle_t sc_ioh; | | 107 | bus_space_handle_t sc_ioh; |
108 | bus_dma_tag_t sc_dmat; | | 108 | bus_dma_tag_t sc_dmat; |
109 | uint8_t sc_enaddr[ETHER_ADDR_LEN]; | | 109 | uint8_t sc_enaddr[ETHER_ADDR_LEN]; |
110 | struct ethercom sc_ethercom; | | 110 | struct ethercom sc_ethercom; |
111 | mii_data_t sc_mii; | | 111 | mii_data_t sc_mii; |
112 | | | 112 | |
113 | void *rbqpage; | | 113 | void *rbqpage; |
114 | unsigned rbqlen; | | 114 | unsigned rbqlen; |
115 | bus_addr_t rbqpage_dsaddr; | | 115 | bus_addr_t rbqpage_dsaddr; |
116 | bus_dmamap_t rbqpage_dmamap; | | 116 | bus_dmamap_t rbqpage_dmamap; |
117 | void *tbqpage; | | 117 | void *tbqpage; |
118 | unsigned tbqlen; | | 118 | unsigned tbqlen; |
119 | bus_addr_t tbqpage_dsaddr; | | 119 | bus_addr_t tbqpage_dsaddr; |
120 | bus_dmamap_t tbqpage_dmamap; | | 120 | bus_dmamap_t tbqpage_dmamap; |
121 | | | 121 | |
122 | volatile struct eth_dsc *RDSC; | | 122 | volatile struct eth_dsc *RDSC; |
123 | int rxqi; | | 123 | int rxqi; |
124 | struct cemac_qmeta rxq[RX_QLEN]; | | 124 | struct cemac_qmeta rxq[RX_QLEN]; |
125 | volatile struct eth_dsc *TDSC; | | 125 | volatile struct eth_dsc *TDSC; |
126 | int txqi, txqc; | | 126 | int txqi, txqc; |
127 | struct cemac_qmeta txq[TX_QLEN]; | | 127 | struct cemac_qmeta txq[TX_QLEN]; |
128 | callout_t cemac_tick_ch; | | 128 | callout_t cemac_tick_ch; |
129 | | | 129 | |
130 | int cemac_flags; | | 130 | int cemac_flags; |
131 | }; | | 131 | }; |
132 | | | 132 | |
133 | static void cemac_init(struct cemac_softc *); | | 133 | static void cemac_init(struct cemac_softc *); |
134 | static int cemac_gctx(struct cemac_softc *); | | 134 | static int cemac_gctx(struct cemac_softc *); |
135 | static int cemac_mediachange(struct ifnet *); | | 135 | static int cemac_mediachange(struct ifnet *); |
136 | static void cemac_mediastatus(struct ifnet *, struct ifmediareq *); | | 136 | static void cemac_mediastatus(struct ifnet *, struct ifmediareq *); |
137 | static int cemac_mii_readreg(device_t, int, int, uint16_t *); | | 137 | static int cemac_mii_readreg(device_t, int, int, uint16_t *); |
138 | static int cemac_mii_writereg(device_t, int, int, uint16_t); | | 138 | static int cemac_mii_writereg(device_t, int, int, uint16_t); |
139 | static void cemac_statchg(struct ifnet *); | | 139 | static void cemac_statchg(struct ifnet *); |
140 | static void cemac_tick(void *); | | 140 | static void cemac_tick(void *); |
141 | static int cemac_ifioctl(struct ifnet *, u_long, void *); | | 141 | static int cemac_ifioctl(struct ifnet *, u_long, void *); |
142 | static void cemac_ifstart(struct ifnet *); | | 142 | static void cemac_ifstart(struct ifnet *); |
143 | static void cemac_ifwatchdog(struct ifnet *); | | 143 | static void cemac_ifwatchdog(struct ifnet *); |
144 | static int cemac_ifinit(struct ifnet *); | | 144 | static int cemac_ifinit(struct ifnet *); |
145 | static void cemac_ifstop(struct ifnet *, int); | | 145 | static void cemac_ifstop(struct ifnet *, int); |
146 | static void cemac_setaddr(struct ifnet *); | | 146 | static void cemac_setaddr(struct ifnet *); |
147 | | | 147 | |
148 | #ifdef CEMAC_DEBUG | | 148 | #ifdef CEMAC_DEBUG |
149 | int cemac_debug = CEMAC_DEBUG; | | 149 | int cemac_debug = CEMAC_DEBUG; |
150 | #define DPRINTFN(n, fmt) if (cemac_debug >= (n)) printf fmt | | 150 | #define DPRINTFN(n, fmt) if (cemac_debug >= (n)) printf fmt |
151 | #else | | 151 | #else |
152 | #define DPRINTFN(n, fmt) | | 152 | #define DPRINTFN(n, fmt) |
153 | #endif | | 153 | #endif |
154 | | | 154 | |
155 | CFATTACH_DECL_NEW(cemac, sizeof(struct cemac_softc), | | 155 | CFATTACH_DECL_NEW(cemac, sizeof(struct cemac_softc), |
156 | cemac_match, cemac_attach, NULL, NULL); | | 156 | cemac_match, cemac_attach, NULL, NULL); |
157 | | | 157 | |
158 | int | | 158 | int |
159 | cemac_match_common(device_t parent, cfdata_t match, void *aux) | | 159 | cemac_match_common(device_t parent, cfdata_t match, void *aux) |
160 | { | | 160 | { |
161 | if (strcmp(match->cf_name, "cemac") == 0) | | 161 | if (strcmp(match->cf_name, "cemac") == 0) |
162 | return 1; | | 162 | return 1; |
163 | return 0; | | 163 | return 0; |
164 | } | | 164 | } |
165 | | | 165 | |
166 | void | | 166 | void |
167 | cemac_attach_common(device_t self, bus_space_tag_t iot, | | 167 | cemac_attach_common(device_t self, bus_space_tag_t iot, |
168 | bus_space_handle_t ioh, bus_dma_tag_t dmat, int flags) | | 168 | bus_space_handle_t ioh, bus_dma_tag_t dmat, int flags) |
169 | { | | 169 | { |
170 | struct cemac_softc *sc = device_private(self); | | 170 | struct cemac_softc *sc = device_private(self); |
171 | prop_data_t enaddr; | | 171 | prop_data_t enaddr; |
172 | uint32_t u; | | 172 | uint32_t u; |
173 | | | 173 | |
174 | | | 174 | |
175 | sc->sc_dev = self; | | 175 | sc->sc_dev = self; |
176 | sc->sc_ioh = ioh; | | 176 | sc->sc_ioh = ioh; |
177 | sc->sc_iot = iot; | | 177 | sc->sc_iot = iot; |
178 | sc->sc_dmat = dmat; | | 178 | sc->sc_dmat = dmat; |
179 | sc->cemac_flags = flags; | | 179 | sc->cemac_flags = flags; |
180 | | | 180 | |
181 | aprint_naive("\n"); | | 181 | aprint_naive("\n"); |
182 | if (ISSET(sc->cemac_flags, CEMAC_FLAG_GEM)) | | 182 | if (ISSET(sc->cemac_flags, CEMAC_FLAG_GEM)) |
183 | aprint_normal(": Cadence Gigabit Ethernet Controller\n"); | | 183 | aprint_normal(": Cadence Gigabit Ethernet Controller\n"); |
184 | else | | 184 | else |
185 | aprint_normal(": Cadence Ethernet Controller\n"); | | 185 | aprint_normal(": Cadence Ethernet Controller\n"); |
186 | | | 186 | |
187 | /* configure emac: */ | | 187 | /* configure emac: */ |
188 | CEMAC_WRITE(ETH_CTL, 0); // disable everything | | 188 | CEMAC_WRITE(ETH_CTL, 0); // disable everything |
189 | CEMAC_WRITE(ETH_IDR, -1); // disable interrupts | | 189 | CEMAC_WRITE(ETH_IDR, -1); // disable interrupts |
190 | CEMAC_WRITE(ETH_RBQP, 0); // clear receive | | 190 | CEMAC_WRITE(ETH_RBQP, 0); // clear receive |
191 | CEMAC_WRITE(ETH_TBQP, 0); // clear transmit | | 191 | CEMAC_WRITE(ETH_TBQP, 0); // clear transmit |
192 | if (ISSET(sc->cemac_flags, CEMAC_FLAG_GEM)) | | 192 | if (ISSET(sc->cemac_flags, CEMAC_FLAG_GEM)) |
193 | CEMAC_WRITE(ETH_CFG, | | 193 | CEMAC_WRITE(ETH_CFG, |
194 | GEM_CFG_CLK_64 | GEM_CFG_GEN | ETH_CFG_SPD | ETH_CFG_FD); | | 194 | GEM_CFG_CLK_64 | GEM_CFG_GEN | ETH_CFG_SPD | ETH_CFG_FD); |
195 | else | | 195 | else |
196 | CEMAC_WRITE(ETH_CFG, | | 196 | CEMAC_WRITE(ETH_CFG, |
197 | ETH_CFG_CLK_32 | ETH_CFG_SPD | ETH_CFG_FD | ETH_CFG_BIG); | | 197 | ETH_CFG_CLK_32 | ETH_CFG_SPD | ETH_CFG_FD | ETH_CFG_BIG); |
198 | //CEMAC_WRITE(ETH_TCR, 0); // send nothing | | 198 | //CEMAC_WRITE(ETH_TCR, 0); // send nothing |
199 | //(void)CEMAC_READ(ETH_ISR); | | 199 | //(void)CEMAC_READ(ETH_ISR); |
200 | u = CEMAC_READ(ETH_TSR); | | 200 | u = CEMAC_READ(ETH_TSR); |
201 | CEMAC_WRITE(ETH_TSR, (u & (ETH_TSR_UND | ETH_TSR_COMP | ETH_TSR_BNQ | | 201 | CEMAC_WRITE(ETH_TSR, (u & (ETH_TSR_UND | ETH_TSR_COMP | ETH_TSR_BNQ |
202 | | ETH_TSR_IDLE | ETH_TSR_RLE | | 202 | | ETH_TSR_IDLE | ETH_TSR_RLE |
203 | | ETH_TSR_COL | ETH_TSR_OVR))); | | 203 | | ETH_TSR_COL | ETH_TSR_OVR))); |
204 | u = CEMAC_READ(ETH_RSR); | | 204 | u = CEMAC_READ(ETH_RSR); |
205 | CEMAC_WRITE(ETH_RSR, (u & (ETH_RSR_OVR | ETH_RSR_REC | ETH_RSR_BNA))); | | 205 | CEMAC_WRITE(ETH_RSR, (u & (ETH_RSR_OVR | ETH_RSR_REC | ETH_RSR_BNA))); |
206 | | | 206 | |
207 | /* Fetch the Ethernet address from property if set. */ | | 207 | /* Fetch the Ethernet address from property if set. */ |
208 | enaddr = prop_dictionary_get(device_properties(self), "mac-address"); | | 208 | enaddr = prop_dictionary_get(device_properties(self), "mac-address"); |
209 | | | 209 | |
210 | if (enaddr != NULL) { | | 210 | if (enaddr != NULL) { |
211 | KASSERT(prop_object_type(enaddr) == PROP_TYPE_DATA); | | 211 | KASSERT(prop_object_type(enaddr) == PROP_TYPE_DATA); |
212 | KASSERT(prop_data_size(enaddr) == ETHER_ADDR_LEN); | | 212 | KASSERT(prop_data_size(enaddr) == ETHER_ADDR_LEN); |
213 | memcpy(sc->sc_enaddr, prop_data_data_nocopy(enaddr), | | 213 | memcpy(sc->sc_enaddr, prop_data_data_nocopy(enaddr), |
214 | ETHER_ADDR_LEN); | | 214 | ETHER_ADDR_LEN); |
215 | } else { | | 215 | } else { |
216 | static const uint8_t hardcoded[ETHER_ADDR_LEN] = { | | 216 | static const uint8_t hardcoded[ETHER_ADDR_LEN] = { |
217 | 0x00, 0x0d, 0x10, 0x81, 0x0c, 0x94 | | 217 | 0x00, 0x0d, 0x10, 0x81, 0x0c, 0x94 |
218 | }; | | 218 | }; |
219 | memcpy(sc->sc_enaddr, hardcoded, ETHER_ADDR_LEN); | | 219 | memcpy(sc->sc_enaddr, hardcoded, ETHER_ADDR_LEN); |
220 | } | | 220 | } |
221 | | | 221 | |
222 | cemac_init(sc); | | 222 | cemac_init(sc); |
223 | } | | 223 | } |
224 | | | 224 | |
225 | static int | | 225 | static int |
226 | cemac_gctx(struct cemac_softc *sc) | | 226 | cemac_gctx(struct cemac_softc *sc) |
227 | { | | 227 | { |
228 | struct ifnet * ifp = &sc->sc_ethercom.ec_if; | | 228 | struct ifnet * ifp = &sc->sc_ethercom.ec_if; |
229 | uint32_t tsr; | | 229 | uint32_t tsr; |
230 | | | 230 | |
231 | tsr = CEMAC_READ(ETH_TSR); | | 231 | tsr = CEMAC_READ(ETH_TSR); |
232 | if (!ISSET(sc->cemac_flags, CEMAC_FLAG_GEM)) { | | 232 | if (!ISSET(sc->cemac_flags, CEMAC_FLAG_GEM)) { |
233 | // no space left | | 233 | // no space left |
234 | if (!(tsr & ETH_TSR_BNQ)) | | 234 | if (!(tsr & ETH_TSR_BNQ)) |
235 | return 0; | | 235 | return 0; |
236 | } else { | | 236 | } else { |
237 | if (tsr & GEM_TSR_TXGO) | | 237 | if (tsr & GEM_TSR_TXGO) |
238 | return 0; | | 238 | return 0; |
239 | } | | 239 | } |
240 | CEMAC_WRITE(ETH_TSR, tsr); | | 240 | CEMAC_WRITE(ETH_TSR, tsr); |
241 | | | 241 | |
242 | // free sent frames | | 242 | // free sent frames |
243 | while (sc->txqc > (ISSET(sc->cemac_flags, CEMAC_FLAG_GEM) ? 0 : | | 243 | while (sc->txqc > (ISSET(sc->cemac_flags, CEMAC_FLAG_GEM) ? 0 : |
244 | (tsr & ETH_TSR_IDLE ? 0 : 1))) { | | 244 | (tsr & ETH_TSR_IDLE ? 0 : 1))) { |
245 | int bi = sc->txqi % TX_QLEN; | | 245 | int bi = sc->txqi % TX_QLEN; |
246 | | | 246 | |
247 | DPRINTFN(3,("%s: TDSC[%i].Addr 0x%08x\n", | | 247 | DPRINTFN(3,("%s: TDSC[%i].Addr 0x%08x\n", |
248 | __FUNCTION__, bi, sc->TDSC[bi].Addr)); | | 248 | __FUNCTION__, bi, sc->TDSC[bi].Addr)); |
249 | DPRINTFN(3,("%s: TDSC[%i].Info 0x%08x\n", | | 249 | DPRINTFN(3,("%s: TDSC[%i].Info 0x%08x\n", |
250 | __FUNCTION__, bi, sc->TDSC[bi].Info)); | | 250 | __FUNCTION__, bi, sc->TDSC[bi].Info)); |
251 | | | 251 | |
252 | bus_dmamap_sync(sc->sc_dmat, sc->txq[bi].m_dmamap, 0, | | 252 | bus_dmamap_sync(sc->sc_dmat, sc->txq[bi].m_dmamap, 0, |
253 | sc->txq[bi].m->m_pkthdr.len, BUS_DMASYNC_POSTWRITE); | | 253 | sc->txq[bi].m->m_pkthdr.len, BUS_DMASYNC_POSTWRITE); |
254 | bus_dmamap_unload(sc->sc_dmat, sc->txq[bi].m_dmamap); | | 254 | bus_dmamap_unload(sc->sc_dmat, sc->txq[bi].m_dmamap); |
255 | m_freem(sc->txq[bi].m); | | 255 | m_freem(sc->txq[bi].m); |
256 | DPRINTFN(2,("%s: freed idx #%i mbuf %p (txqc=%i)\n", | | 256 | DPRINTFN(2,("%s: freed idx #%i mbuf %p (txqc=%i)\n", |
257 | __FUNCTION__, bi, sc->txq[bi].m, sc->txqc)); | | 257 | __FUNCTION__, bi, sc->txq[bi].m, sc->txqc)); |
258 | sc->txq[bi].m = NULL; | | 258 | sc->txq[bi].m = NULL; |
259 | sc->txqi = (bi + 1) % TX_QLEN; | | 259 | sc->txqi = (bi + 1) % TX_QLEN; |
260 | sc->txqc--; | | 260 | sc->txqc--; |
261 | } | | 261 | } |
262 | | | 262 | |
263 | // mark we're free | | 263 | // mark we're free |
264 | if (ifp->if_flags & IFF_OACTIVE) { | | 264 | if (ifp->if_flags & IFF_OACTIVE) { |
265 | ifp->if_flags &= ~IFF_OACTIVE; | | 265 | ifp->if_flags &= ~IFF_OACTIVE; |
266 | /* Disable transmit-buffer-free interrupt */ | | 266 | /* Disable transmit-buffer-free interrupt */ |
267 | /*CEMAC_WRITE(ETH_IDR, ETH_ISR_TBRE);*/ | | 267 | /*CEMAC_WRITE(ETH_IDR, ETH_ISR_TBRE);*/ |
268 | } | | 268 | } |
269 | | | 269 | |
270 | return 1; | | 270 | return 1; |
271 | } | | 271 | } |
272 | | | 272 | |
273 | int | | 273 | int |
274 | cemac_intr(void *arg) | | 274 | cemac_intr(void *arg) |
275 | { | | 275 | { |
276 | struct cemac_softc *sc = (struct cemac_softc *)arg; | | 276 | struct cemac_softc *sc = (struct cemac_softc *)arg; |
277 | struct ifnet * ifp = &sc->sc_ethercom.ec_if; | | 277 | struct ifnet * ifp = &sc->sc_ethercom.ec_if; |
278 | uint32_t imr, isr, ctl; | | 278 | uint32_t imr, isr, ctl; |
279 | #ifdef CEMAC_DEBUG | | 279 | #ifdef CEMAC_DEBUG |
280 | uint32_t rsr; | | 280 | uint32_t rsr; |
281 | #endif | | 281 | #endif |
282 | int bi; | | 282 | int bi; |
283 | | | 283 | |
284 | imr = ~CEMAC_READ(ETH_IMR); | | 284 | imr = ~CEMAC_READ(ETH_IMR); |
285 | if (!(imr & (ETH_ISR_RCOM | ETH_ISR_TBRE | ETH_ISR_TIDLE | | | 285 | if (!(imr & (ETH_ISR_RCOM | ETH_ISR_TBRE | ETH_ISR_TIDLE | |
286 | ETH_ISR_RBNA | ETH_ISR_ROVR | ETH_ISR_TCOM))) { | | 286 | ETH_ISR_RBNA | ETH_ISR_ROVR | ETH_ISR_TCOM))) { |
287 | // interrupt not enabled, can't be us | | 287 | // interrupt not enabled, can't be us |
288 | return 0; | | 288 | return 0; |
289 | } | | 289 | } |
290 | | | 290 | |
291 | isr = CEMAC_READ(ETH_ISR); | | 291 | isr = CEMAC_READ(ETH_ISR); |
292 | CEMAC_WRITE(ETH_ISR, isr); | | 292 | CEMAC_WRITE(ETH_ISR, isr); |
293 | isr &= imr; | | 293 | isr &= imr; |
294 | #ifdef CEMAC_DEBUG | | 294 | #ifdef CEMAC_DEBUG |
295 | rsr = CEMAC_READ(ETH_RSR); // get receive status register | | 295 | rsr = CEMAC_READ(ETH_RSR); // get receive status register |
296 | #endif | | 296 | #endif |
297 | DPRINTFN(2, ("%s: isr=0x%08X rsr=0x%08X imr=0x%08X\n", __FUNCTION__, isr, rsr, imr)); | | 297 | DPRINTFN(2, ("%s: isr=0x%08X rsr=0x%08X imr=0x%08X\n", __FUNCTION__, isr, rsr, imr)); |
298 | | | 298 | |
| | | 299 | net_stat_ref_t nsr = IF_STAT_GETREF(ifp); |
299 | if (isr & ETH_ISR_RBNA) { // out of receive buffers | | 300 | if (isr & ETH_ISR_RBNA) { // out of receive buffers |
300 | CEMAC_WRITE(ETH_RSR, ETH_RSR_BNA); // clear interrupt | | 301 | CEMAC_WRITE(ETH_RSR, ETH_RSR_BNA); // clear interrupt |
301 | ctl = CEMAC_READ(ETH_CTL); // get current control register value | | 302 | ctl = CEMAC_READ(ETH_CTL); // get current control register value |
302 | CEMAC_WRITE(ETH_CTL, ctl & ~ETH_CTL_RE); // disable receiver | | 303 | CEMAC_WRITE(ETH_CTL, ctl & ~ETH_CTL_RE); // disable receiver |
303 | CEMAC_WRITE(ETH_RSR, ETH_RSR_BNA); // clear BNA bit | | 304 | CEMAC_WRITE(ETH_RSR, ETH_RSR_BNA); // clear BNA bit |
304 | CEMAC_WRITE(ETH_CTL, ctl | ETH_CTL_RE); // re-enable receiver | | 305 | CEMAC_WRITE(ETH_CTL, ctl | ETH_CTL_RE); // re-enable receiver |
305 | ifp->if_ierrors++; | | 306 | if_statinc_ref(nsr, if_ierrors); |
306 | ifp->if_ipackets++; | | 307 | if_statinc_ref(nsr, if_ipackets); |
307 | DPRINTFN(1,("%s: out of receive buffers\n", __FUNCTION__)); | | 308 | DPRINTFN(1,("%s: out of receive buffers\n", __FUNCTION__)); |
308 | } | | 309 | } |
309 | if (isr & ETH_ISR_ROVR) { | | 310 | if (isr & ETH_ISR_ROVR) { |
310 | CEMAC_WRITE(ETH_RSR, ETH_RSR_OVR); // clear interrupt | | 311 | CEMAC_WRITE(ETH_RSR, ETH_RSR_OVR); // clear interrupt |
311 | ifp->if_ierrors++; | | 312 | if_statinc_ref(nsr, if_ierrors); |
312 | ifp->if_ipackets++; | | 313 | if_statinc_ref(nsr, if_ipackets); |
313 | DPRINTFN(1,("%s: receive overrun\n", __FUNCTION__)); | | 314 | DPRINTFN(1,("%s: receive overrun\n", __FUNCTION__)); |
314 | } | | 315 | } |
315 | | | 316 | |
316 | if (isr & ETH_ISR_RCOM) { // packet has been received! | | 317 | if (isr & ETH_ISR_RCOM) { // packet has been received! |
317 | uint32_t nfo; | | 318 | uint32_t nfo; |
318 | DPRINTFN(2,("#2 RDSC[%i].INFO=0x%08X\n", sc->rxqi % RX_QLEN, sc->RDSC[sc->rxqi % RX_QLEN].Info)); | | 319 | DPRINTFN(2,("#2 RDSC[%i].INFO=0x%08X\n", sc->rxqi % RX_QLEN, sc->RDSC[sc->rxqi % RX_QLEN].Info)); |
319 | while (sc->RDSC[(bi = sc->rxqi % RX_QLEN)].Addr & ETH_RDSC_F_USED) { | | 320 | while (sc->RDSC[(bi = sc->rxqi % RX_QLEN)].Addr & ETH_RDSC_F_USED) { |
320 | int fl, csum; | | 321 | int fl, csum; |
321 | struct mbuf *m; | | 322 | struct mbuf *m; |
322 | | | 323 | |
323 | nfo = sc->RDSC[bi].Info; | | 324 | nfo = sc->RDSC[bi].Info; |
324 | fl = (nfo & ETH_RDSC_I_LEN) - 4; | | 325 | fl = (nfo & ETH_RDSC_I_LEN) - 4; |
325 | DPRINTFN(2,("## nfo=0x%08X\n", nfo)); | | 326 | DPRINTFN(2,("## nfo=0x%08X\n", nfo)); |
326 | | | 327 | |
327 | MGETHDR(m, M_DONTWAIT, MT_DATA); | | 328 | MGETHDR(m, M_DONTWAIT, MT_DATA); |
328 | if (m != NULL) MCLGET(m, M_DONTWAIT); | | 329 | if (m != NULL) MCLGET(m, M_DONTWAIT); |
329 | if (m != NULL && (m->m_flags & M_EXT)) { | | 330 | if (m != NULL && (m->m_flags & M_EXT)) { |
330 | bus_dmamap_sync(sc->sc_dmat, sc->rxq[bi].m_dmamap, 0, | | 331 | bus_dmamap_sync(sc->sc_dmat, sc->rxq[bi].m_dmamap, 0, |
331 | MCLBYTES, BUS_DMASYNC_POSTREAD); | | 332 | MCLBYTES, BUS_DMASYNC_POSTREAD); |
332 | bus_dmamap_unload(sc->sc_dmat, | | 333 | bus_dmamap_unload(sc->sc_dmat, |
333 | sc->rxq[bi].m_dmamap); | | 334 | sc->rxq[bi].m_dmamap); |
334 | m_set_rcvif(sc->rxq[bi].m, ifp); | | 335 | m_set_rcvif(sc->rxq[bi].m, ifp); |
335 | sc->rxq[bi].m->m_pkthdr.len = | | 336 | sc->rxq[bi].m->m_pkthdr.len = |
336 | sc->rxq[bi].m->m_len = fl; | | 337 | sc->rxq[bi].m->m_len = fl; |
337 | switch (nfo & ETH_RDSC_I_CHKSUM) { | | 338 | switch (nfo & ETH_RDSC_I_CHKSUM) { |
338 | case ETH_RDSC_I_CHKSUM_IP: | | 339 | case ETH_RDSC_I_CHKSUM_IP: |
339 | csum = M_CSUM_IPv4; | | 340 | csum = M_CSUM_IPv4; |
340 | break; | | 341 | break; |
341 | case ETH_RDSC_I_CHKSUM_UDP: | | 342 | case ETH_RDSC_I_CHKSUM_UDP: |
342 | csum = M_CSUM_IPv4 | M_CSUM_UDPv4 | | | 343 | csum = M_CSUM_IPv4 | M_CSUM_UDPv4 | |
343 | M_CSUM_UDPv6; | | 344 | M_CSUM_UDPv6; |
344 | break; | | 345 | break; |
345 | case ETH_RDSC_I_CHKSUM_TCP: | | 346 | case ETH_RDSC_I_CHKSUM_TCP: |
346 | csum = M_CSUM_IPv4 | M_CSUM_TCPv4 | | | 347 | csum = M_CSUM_IPv4 | M_CSUM_TCPv4 | |
347 | M_CSUM_TCPv6; | | 348 | M_CSUM_TCPv6; |
348 | break; | | 349 | break; |
349 | default: | | 350 | default: |
350 | csum = 0; | | 351 | csum = 0; |
351 | break; | | 352 | break; |
352 | } | | 353 | } |
353 | sc->rxq[bi].m->m_pkthdr.csum_flags = csum; | | 354 | sc->rxq[bi].m->m_pkthdr.csum_flags = csum; |
354 | DPRINTFN(2,("received %u bytes packet\n", fl)); | | 355 | DPRINTFN(2,("received %u bytes packet\n", fl)); |
355 | if_percpuq_enqueue(ifp->if_percpuq, | | 356 | if_percpuq_enqueue(ifp->if_percpuq, |
356 | sc->rxq[bi].m); | | 357 | sc->rxq[bi].m); |
357 | if (mtod(m, intptr_t) & 3) | | 358 | if (mtod(m, intptr_t) & 3) |
358 | m_adj(m, mtod(m, intptr_t) & 3); | | 359 | m_adj(m, mtod(m, intptr_t) & 3); |
359 | sc->rxq[bi].m = m; | | 360 | sc->rxq[bi].m = m; |
360 | bus_dmamap_load(sc->sc_dmat, | | 361 | bus_dmamap_load(sc->sc_dmat, |
361 | sc->rxq[bi].m_dmamap, | | 362 | sc->rxq[bi].m_dmamap, |
362 | m->m_ext.ext_buf, MCLBYTES, | | 363 | m->m_ext.ext_buf, MCLBYTES, |
363 | NULL, BUS_DMA_NOWAIT); | | 364 | NULL, BUS_DMA_NOWAIT); |
364 | bus_dmamap_sync(sc->sc_dmat, sc->rxq[bi].m_dmamap, 0, | | 365 | bus_dmamap_sync(sc->sc_dmat, sc->rxq[bi].m_dmamap, 0, |
365 | MCLBYTES, BUS_DMASYNC_PREREAD); | | 366 | MCLBYTES, BUS_DMASYNC_PREREAD); |
366 | sc->RDSC[bi].Info = 0; | | 367 | sc->RDSC[bi].Info = 0; |
367 | sc->RDSC[bi].Addr = | | 368 | sc->RDSC[bi].Addr = |
368 | sc->rxq[bi].m_dmamap->dm_segs[0].ds_addr | | 369 | sc->rxq[bi].m_dmamap->dm_segs[0].ds_addr |
369 | | (bi == (RX_QLEN-1) ? ETH_RDSC_F_WRAP : 0); | | 370 | | (bi == (RX_QLEN-1) ? ETH_RDSC_F_WRAP : 0); |
370 | } else { | | 371 | } else { |
371 | /* Drop packets until we can get replacement | | 372 | /* Drop packets until we can get replacement |
372 | * empty mbufs for the RXDQ. | | 373 | * empty mbufs for the RXDQ. |
373 | */ | | 374 | */ |
374 | if (m != NULL) | | 375 | if (m != NULL) |
375 | m_freem(m); | | 376 | m_freem(m); |
376 | ifp->if_ierrors++; | | 377 | if_statinc_ref(nsr, if_ierrors); |
377 | } | | 378 | } |
378 | sc->rxqi++; | | 379 | sc->rxqi++; |
379 | } | | 380 | } |
380 | } | | 381 | } |
381 | | | 382 | |
| | | 383 | IF_STAT_PUTREF(ifp); |
| | | 384 | |
382 | if (cemac_gctx(sc) > 0) | | 385 | if (cemac_gctx(sc) > 0) |
383 | if_schedule_deferred_start(ifp); | | 386 | if_schedule_deferred_start(ifp); |
384 | #if 0 // reloop | | 387 | #if 0 // reloop |
385 | irq = CEMAC_READ(IntStsC); | | 388 | irq = CEMAC_READ(IntStsC); |
386 | if ((irq & (IntSts_RxSQ | IntSts_ECI)) != 0) | | 389 | if ((irq & (IntSts_RxSQ | IntSts_ECI)) != 0) |
387 | goto begin; | | 390 | goto begin; |
388 | #endif | | 391 | #endif |
389 | | | 392 | |
390 | return (1); | | 393 | return (1); |
391 | } | | 394 | } |
392 | | | 395 | |
393 | | | 396 | |
394 | static void | | 397 | static void |
395 | cemac_init(struct cemac_softc *sc) | | 398 | cemac_init(struct cemac_softc *sc) |
396 | { | | 399 | { |
397 | bus_dma_segment_t segs; | | 400 | bus_dma_segment_t segs; |
398 | int rsegs, err, i; | | 401 | int rsegs, err, i; |
399 | struct ifnet * ifp = &sc->sc_ethercom.ec_if; | | 402 | struct ifnet * ifp = &sc->sc_ethercom.ec_if; |
400 | struct mii_data * const mii = &sc->sc_mii; | | 403 | struct mii_data * const mii = &sc->sc_mii; |
401 | uint32_t u; | | 404 | uint32_t u; |
402 | #if 0 | | 405 | #if 0 |
403 | int mdcdiv = DEFAULT_MDCDIV; | | 406 | int mdcdiv = DEFAULT_MDCDIV; |
404 | #endif | | 407 | #endif |
405 | | | 408 | |
406 | callout_init(&sc->cemac_tick_ch, 0); | | 409 | callout_init(&sc->cemac_tick_ch, 0); |
407 | | | 410 | |
408 | // ok... | | 411 | // ok... |
409 | CEMAC_WRITE(ETH_CTL, ETH_CTL_MPE); // disable everything | | 412 | CEMAC_WRITE(ETH_CTL, ETH_CTL_MPE); // disable everything |
410 | CEMAC_WRITE(ETH_IDR, -1); // disable interrupts | | 413 | CEMAC_WRITE(ETH_IDR, -1); // disable interrupts |
411 | CEMAC_WRITE(ETH_RBQP, 0); // clear receive | | 414 | CEMAC_WRITE(ETH_RBQP, 0); // clear receive |
412 | CEMAC_WRITE(ETH_TBQP, 0); // clear transmit | | 415 | CEMAC_WRITE(ETH_TBQP, 0); // clear transmit |
413 | if (ISSET(sc->cemac_flags, CEMAC_FLAG_GEM)) | | 416 | if (ISSET(sc->cemac_flags, CEMAC_FLAG_GEM)) |
414 | CEMAC_WRITE(ETH_CFG, | | 417 | CEMAC_WRITE(ETH_CFG, |
415 | GEM_CFG_CLK_64 | ETH_CFG_SPD | ETH_CFG_FD | ETH_CFG_BIG); | | 418 | GEM_CFG_CLK_64 | ETH_CFG_SPD | ETH_CFG_FD | ETH_CFG_BIG); |
416 | else | | 419 | else |
417 | CEMAC_WRITE(ETH_CFG, | | 420 | CEMAC_WRITE(ETH_CFG, |
418 | ETH_CFG_CLK_32 | ETH_CFG_SPD | ETH_CFG_FD | ETH_CFG_BIG); | | 421 | ETH_CFG_CLK_32 | ETH_CFG_SPD | ETH_CFG_FD | ETH_CFG_BIG); |
419 | if (ISSET(sc->cemac_flags, CEMAC_FLAG_GEM)) { | | 422 | if (ISSET(sc->cemac_flags, CEMAC_FLAG_GEM)) { |
420 | CEMAC_WRITE(GEM_DMA_CFG, | | 423 | CEMAC_WRITE(GEM_DMA_CFG, |
421 | __SHIFTIN((MCLBYTES + 63) / 64, GEM_DMA_CFG_RX_BUF_SIZE) | | | 424 | __SHIFTIN((MCLBYTES + 63) / 64, GEM_DMA_CFG_RX_BUF_SIZE) | |
422 | __SHIFTIN(3, GEM_DMA_CFG_RX_PKTBUF_MEMSZ_SEL) | | | 425 | __SHIFTIN(3, GEM_DMA_CFG_RX_PKTBUF_MEMSZ_SEL) | |
423 | GEM_DMA_CFG_TX_PKTBUF_MEMSZ_SEL | | | 426 | GEM_DMA_CFG_TX_PKTBUF_MEMSZ_SEL | |
424 | __SHIFTIN(16, GEM_DMA_CFG_AHB_FIXED_BURST_LEN) | | | 427 | __SHIFTIN(16, GEM_DMA_CFG_AHB_FIXED_BURST_LEN) | |
425 | GEM_DMA_CFG_DISC_WHEN_NO_AHB); | | 428 | GEM_DMA_CFG_DISC_WHEN_NO_AHB); |
426 | } | | 429 | } |
427 | // CEMAC_WRITE(ETH_TCR, 0); // send nothing | | 430 | // CEMAC_WRITE(ETH_TCR, 0); // send nothing |
428 | // (void)CEMAC_READ(ETH_ISR); | | 431 | // (void)CEMAC_READ(ETH_ISR); |
429 | u = CEMAC_READ(ETH_TSR); | | 432 | u = CEMAC_READ(ETH_TSR); |
430 | CEMAC_WRITE(ETH_TSR, (u & (ETH_TSR_UND | ETH_TSR_COMP | ETH_TSR_BNQ | | 433 | CEMAC_WRITE(ETH_TSR, (u & (ETH_TSR_UND | ETH_TSR_COMP | ETH_TSR_BNQ |
431 | | ETH_TSR_IDLE | ETH_TSR_RLE | | 434 | | ETH_TSR_IDLE | ETH_TSR_RLE |
432 | | ETH_TSR_COL | ETH_TSR_OVR))); | | 435 | | ETH_TSR_COL | ETH_TSR_OVR))); |
433 | u = CEMAC_READ(ETH_RSR); | | 436 | u = CEMAC_READ(ETH_RSR); |
434 | CEMAC_WRITE(ETH_RSR, (u & (ETH_RSR_OVR | ETH_RSR_REC | ETH_RSR_BNA))); | | 437 | CEMAC_WRITE(ETH_RSR, (u & (ETH_RSR_OVR | ETH_RSR_REC | ETH_RSR_BNA))); |
435 | | | 438 | |
436 | #if 0 | | 439 | #if 0 |
437 | if (device_cfdata(sc->sc_dev)->cf_flags) | | 440 | if (device_cfdata(sc->sc_dev)->cf_flags) |
438 | mdcdiv = device_cfdata(sc->sc_dev)->cf_flags; | | 441 | mdcdiv = device_cfdata(sc->sc_dev)->cf_flags; |
439 | #endif | | 442 | #endif |
440 | /* set ethernet address */ | | 443 | /* set ethernet address */ |
441 | CEMAC_GEM_WRITE(SA1L, (sc->sc_enaddr[3] << 24) | | 444 | CEMAC_GEM_WRITE(SA1L, (sc->sc_enaddr[3] << 24) |
442 | | (sc->sc_enaddr[2] << 16) | (sc->sc_enaddr[1] << 8) | | 445 | | (sc->sc_enaddr[2] << 16) | (sc->sc_enaddr[1] << 8) |
443 | | (sc->sc_enaddr[0])); | | 446 | | (sc->sc_enaddr[0])); |
444 | CEMAC_GEM_WRITE(SA1H, (sc->sc_enaddr[5] << 8) | | 447 | CEMAC_GEM_WRITE(SA1H, (sc->sc_enaddr[5] << 8) |
445 | | (sc->sc_enaddr[4])); | | 448 | | (sc->sc_enaddr[4])); |
446 | CEMAC_GEM_WRITE(SA2L, 0); | | 449 | CEMAC_GEM_WRITE(SA2L, 0); |
447 | CEMAC_GEM_WRITE(SA2H, 0); | | 450 | CEMAC_GEM_WRITE(SA2H, 0); |
448 | CEMAC_GEM_WRITE(SA3L, 0); | | 451 | CEMAC_GEM_WRITE(SA3L, 0); |
449 | CEMAC_GEM_WRITE(SA3H, 0); | | 452 | CEMAC_GEM_WRITE(SA3H, 0); |
450 | CEMAC_GEM_WRITE(SA4L, 0); | | 453 | CEMAC_GEM_WRITE(SA4L, 0); |
451 | CEMAC_GEM_WRITE(SA4H, 0); | | 454 | CEMAC_GEM_WRITE(SA4H, 0); |
452 | | | 455 | |
453 | /* Allocate a page of memory for receive queue descriptors */ | | 456 | /* Allocate a page of memory for receive queue descriptors */ |
454 | sc->rbqlen = (ETH_DSC_SIZE * (RX_QLEN + 1) * 2 + PAGE_SIZE - 1) / PAGE_SIZE; | | 457 | sc->rbqlen = (ETH_DSC_SIZE * (RX_QLEN + 1) * 2 + PAGE_SIZE - 1) / PAGE_SIZE; |
455 | sc->rbqlen *= PAGE_SIZE; | | 458 | sc->rbqlen *= PAGE_SIZE; |
456 | DPRINTFN(1,("%s: rbqlen=%i\n", __FUNCTION__, sc->rbqlen)); | | 459 | DPRINTFN(1,("%s: rbqlen=%i\n", __FUNCTION__, sc->rbqlen)); |
457 | | | 460 | |
458 | err = bus_dmamem_alloc(sc->sc_dmat, sc->rbqlen, 0, | | 461 | err = bus_dmamem_alloc(sc->sc_dmat, sc->rbqlen, 0, |
459 | MAX(16384, PAGE_SIZE), // see EMAC errata why forced to 16384 byte boundary | | 462 | MAX(16384, PAGE_SIZE), // see EMAC errata why forced to 16384 byte boundary |
460 | &segs, 1, &rsegs, BUS_DMA_WAITOK); | | 463 | &segs, 1, &rsegs, BUS_DMA_WAITOK); |
461 | if (err == 0) { | | 464 | if (err == 0) { |
462 | DPRINTFN(1,("%s: -> bus_dmamem_map\n", __FUNCTION__)); | | 465 | DPRINTFN(1,("%s: -> bus_dmamem_map\n", __FUNCTION__)); |
463 | err = bus_dmamem_map(sc->sc_dmat, &segs, 1, sc->rbqlen, | | 466 | err = bus_dmamem_map(sc->sc_dmat, &segs, 1, sc->rbqlen, |
464 | &sc->rbqpage, (BUS_DMA_WAITOK | BUS_DMA_COHERENT)); | | 467 | &sc->rbqpage, (BUS_DMA_WAITOK | BUS_DMA_COHERENT)); |
465 | } | | 468 | } |
466 | if (err == 0) { | | 469 | if (err == 0) { |
467 | DPRINTFN(1,("%s: -> bus_dmamap_create\n", __FUNCTION__)); | | 470 | DPRINTFN(1,("%s: -> bus_dmamap_create\n", __FUNCTION__)); |
468 | err = bus_dmamap_create(sc->sc_dmat, sc->rbqlen, 1, | | 471 | err = bus_dmamap_create(sc->sc_dmat, sc->rbqlen, 1, |
469 | sc->rbqlen, MAX(16384, PAGE_SIZE), BUS_DMA_WAITOK, | | 472 | sc->rbqlen, MAX(16384, PAGE_SIZE), BUS_DMA_WAITOK, |
470 | &sc->rbqpage_dmamap); | | 473 | &sc->rbqpage_dmamap); |
471 | } | | 474 | } |
472 | if (err == 0) { | | 475 | if (err == 0) { |
473 | DPRINTFN(1,("%s: -> bus_dmamap_load\n", __FUNCTION__)); | | 476 | DPRINTFN(1,("%s: -> bus_dmamap_load\n", __FUNCTION__)); |
474 | err = bus_dmamap_load(sc->sc_dmat, sc->rbqpage_dmamap, | | 477 | err = bus_dmamap_load(sc->sc_dmat, sc->rbqpage_dmamap, |
475 | sc->rbqpage, sc->rbqlen, NULL, BUS_DMA_WAITOK); | | 478 | sc->rbqpage, sc->rbqlen, NULL, BUS_DMA_WAITOK); |
476 | } | | 479 | } |
477 | if (err != 0) | | 480 | if (err != 0) |
478 | panic("%s: Cannot get DMA memory", device_xname(sc->sc_dev)); | | 481 | panic("%s: Cannot get DMA memory", device_xname(sc->sc_dev)); |
479 | | | 482 | |
480 | sc->rbqpage_dsaddr = sc->rbqpage_dmamap->dm_segs[0].ds_addr; | | 483 | sc->rbqpage_dsaddr = sc->rbqpage_dmamap->dm_segs[0].ds_addr; |
481 | memset(sc->rbqpage, 0, sc->rbqlen); | | 484 | memset(sc->rbqpage, 0, sc->rbqlen); |
482 | | | 485 | |
483 | /* Allocate a page of memory for transmit queue descriptors */ | | 486 | /* Allocate a page of memory for transmit queue descriptors */ |
484 | sc->tbqlen = (ETH_DSC_SIZE * (TX_QLEN + 1) * 2 + PAGE_SIZE - 1) / PAGE_SIZE; | | 487 | sc->tbqlen = (ETH_DSC_SIZE * (TX_QLEN + 1) * 2 + PAGE_SIZE - 1) / PAGE_SIZE; |
485 | sc->tbqlen *= PAGE_SIZE; | | 488 | sc->tbqlen *= PAGE_SIZE; |
486 | DPRINTFN(1,("%s: tbqlen=%i\n", __FUNCTION__, sc->tbqlen)); | | 489 | DPRINTFN(1,("%s: tbqlen=%i\n", __FUNCTION__, sc->tbqlen)); |
487 | | | 490 | |
488 | err = bus_dmamem_alloc(sc->sc_dmat, sc->tbqlen, 0, | | 491 | err = bus_dmamem_alloc(sc->sc_dmat, sc->tbqlen, 0, |
489 | MAX(16384, PAGE_SIZE), // see EMAC errata why forced to 16384 byte boundary | | 492 | MAX(16384, PAGE_SIZE), // see EMAC errata why forced to 16384 byte boundary |
490 | &segs, 1, &rsegs, BUS_DMA_WAITOK); | | 493 | &segs, 1, &rsegs, BUS_DMA_WAITOK); |
491 | if (err == 0) { | | 494 | if (err == 0) { |
492 | DPRINTFN(1,("%s: -> bus_dmamem_map\n", __FUNCTION__)); | | 495 | DPRINTFN(1,("%s: -> bus_dmamem_map\n", __FUNCTION__)); |
493 | err = bus_dmamem_map(sc->sc_dmat, &segs, 1, sc->tbqlen, | | 496 | err = bus_dmamem_map(sc->sc_dmat, &segs, 1, sc->tbqlen, |
494 | &sc->tbqpage, (BUS_DMA_WAITOK | BUS_DMA_COHERENT)); | | 497 | &sc->tbqpage, (BUS_DMA_WAITOK | BUS_DMA_COHERENT)); |
495 | } | | 498 | } |
496 | if (err == 0) { | | 499 | if (err == 0) { |
497 | DPRINTFN(1,("%s: -> bus_dmamap_create\n", __FUNCTION__)); | | 500 | DPRINTFN(1,("%s: -> bus_dmamap_create\n", __FUNCTION__)); |
498 | err = bus_dmamap_create(sc->sc_dmat, sc->tbqlen, 1, | | 501 | err = bus_dmamap_create(sc->sc_dmat, sc->tbqlen, 1, |
499 | sc->tbqlen, MAX(16384, PAGE_SIZE), BUS_DMA_WAITOK, | | 502 | sc->tbqlen, MAX(16384, PAGE_SIZE), BUS_DMA_WAITOK, |
500 | &sc->tbqpage_dmamap); | | 503 | &sc->tbqpage_dmamap); |
501 | } | | 504 | } |
502 | if (err == 0) { | | 505 | if (err == 0) { |
503 | DPRINTFN(1,("%s: -> bus_dmamap_load\n", __FUNCTION__)); | | 506 | DPRINTFN(1,("%s: -> bus_dmamap_load\n", __FUNCTION__)); |
504 | err = bus_dmamap_load(sc->sc_dmat, sc->tbqpage_dmamap, | | 507 | err = bus_dmamap_load(sc->sc_dmat, sc->tbqpage_dmamap, |
505 | sc->tbqpage, sc->tbqlen, NULL, BUS_DMA_WAITOK); | | 508 | sc->tbqpage, sc->tbqlen, NULL, BUS_DMA_WAITOK); |
506 | } | | 509 | } |
507 | if (err != 0) | | 510 | if (err != 0) |
508 | panic("%s: Cannot get DMA memory", device_xname(sc->sc_dev)); | | 511 | panic("%s: Cannot get DMA memory", device_xname(sc->sc_dev)); |
509 | | | 512 | |
510 | sc->tbqpage_dsaddr = sc->tbqpage_dmamap->dm_segs[0].ds_addr; | | 513 | sc->tbqpage_dsaddr = sc->tbqpage_dmamap->dm_segs[0].ds_addr; |
511 | memset(sc->tbqpage, 0, sc->tbqlen); | | 514 | memset(sc->tbqpage, 0, sc->tbqlen); |
512 | | | 515 | |
513 | /* Set up pointers to start of each queue in kernel addr space. | | 516 | /* Set up pointers to start of each queue in kernel addr space. |
514 | * Each descriptor queue or status queue entry uses 2 words | | 517 | * Each descriptor queue or status queue entry uses 2 words |
515 | */ | | 518 | */ |
516 | sc->RDSC = (void *)sc->rbqpage; | | 519 | sc->RDSC = (void *)sc->rbqpage; |
517 | sc->TDSC = (void *)sc->tbqpage; | | 520 | sc->TDSC = (void *)sc->tbqpage; |
518 | | | 521 | |
519 | /* init TX queue */ | | 522 | /* init TX queue */ |
520 | for (i = 0; i < TX_QLEN; i++) { | | 523 | for (i = 0; i < TX_QLEN; i++) { |
521 | sc->TDSC[i].Addr = 0; | | 524 | sc->TDSC[i].Addr = 0; |
522 | sc->TDSC[i].Info = ETH_TDSC_I_USED | | | 525 | sc->TDSC[i].Info = ETH_TDSC_I_USED | |
523 | (i == (TX_QLEN - 1) ? ETH_TDSC_I_WRAP : 0); | | 526 | (i == (TX_QLEN - 1) ? ETH_TDSC_I_WRAP : 0); |
524 | } | | 527 | } |
525 | | | 528 | |
526 | /* Populate the RXQ with mbufs */ | | 529 | /* Populate the RXQ with mbufs */ |
527 | sc->rxqi = 0; | | 530 | sc->rxqi = 0; |
528 | for (i = 0; i < RX_QLEN; i++) { | | 531 | for (i = 0; i < RX_QLEN; i++) { |
529 | struct mbuf *m; | | 532 | struct mbuf *m; |
530 | | | 533 | |
531 | err = bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1, MCLBYTES, PAGE_SIZE, | | 534 | err = bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1, MCLBYTES, PAGE_SIZE, |
532 | BUS_DMA_WAITOK, &sc->rxq[i].m_dmamap); | | 535 | BUS_DMA_WAITOK, &sc->rxq[i].m_dmamap); |
533 | if (err) { | | 536 | if (err) { |
534 | panic("%s: dmamap_create failed: %i\n", __FUNCTION__, err); | | 537 | panic("%s: dmamap_create failed: %i\n", __FUNCTION__, err); |
535 | } | | 538 | } |
536 | MGETHDR(m, M_WAIT, MT_DATA); | | 539 | MGETHDR(m, M_WAIT, MT_DATA); |
537 | MCLGET(m, M_WAIT); | | 540 | MCLGET(m, M_WAIT); |
538 | sc->rxq[i].m = m; | | 541 | sc->rxq[i].m = m; |
539 | if (mtod(m, intptr_t) & 3) { | | 542 | if (mtod(m, intptr_t) & 3) { |
540 | m_adj(m, mtod(m, intptr_t) & 3); | | 543 | m_adj(m, mtod(m, intptr_t) & 3); |
541 | } | | 544 | } |
542 | err = bus_dmamap_load(sc->sc_dmat, sc->rxq[i].m_dmamap, | | 545 | err = bus_dmamap_load(sc->sc_dmat, sc->rxq[i].m_dmamap, |
543 | m->m_ext.ext_buf, MCLBYTES, NULL, | | 546 | m->m_ext.ext_buf, MCLBYTES, NULL, |
544 | BUS_DMA_WAITOK); | | 547 | BUS_DMA_WAITOK); |
545 | if (err) { | | 548 | if (err) { |
546 | panic("%s: dmamap_load failed: %i\n", __FUNCTION__, err); | | 549 | panic("%s: dmamap_load failed: %i\n", __FUNCTION__, err); |
547 | } | | 550 | } |
548 | sc->RDSC[i].Addr = sc->rxq[i].m_dmamap->dm_segs[0].ds_addr | | 551 | sc->RDSC[i].Addr = sc->rxq[i].m_dmamap->dm_segs[0].ds_addr |
549 | | (i == (RX_QLEN-1) ? ETH_RDSC_F_WRAP : 0); | | 552 | | (i == (RX_QLEN-1) ? ETH_RDSC_F_WRAP : 0); |
550 | sc->RDSC[i].Info = 0; | | 553 | sc->RDSC[i].Info = 0; |
551 | bus_dmamap_sync(sc->sc_dmat, sc->rxq[i].m_dmamap, 0, | | 554 | bus_dmamap_sync(sc->sc_dmat, sc->rxq[i].m_dmamap, 0, |
552 | MCLBYTES, BUS_DMASYNC_PREREAD); | | 555 | MCLBYTES, BUS_DMASYNC_PREREAD); |
553 | } | | 556 | } |
554 | | | 557 | |
555 | /* prepare transmit queue */ | | 558 | /* prepare transmit queue */ |
556 | for (i = 0; i < TX_QLEN; i++) { | | 559 | for (i = 0; i < TX_QLEN; i++) { |
557 | err = bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1, MCLBYTES, 0, | | 560 | err = bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1, MCLBYTES, 0, |
558 | (BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW), | | 561 | (BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW), |
559 | &sc->txq[i].m_dmamap); | | 562 | &sc->txq[i].m_dmamap); |
560 | if (err) | | 563 | if (err) |
561 | panic("ARGH #1"); | | 564 | panic("ARGH #1"); |
562 | sc->txq[i].m = NULL; | | 565 | sc->txq[i].m = NULL; |
563 | } | | 566 | } |
564 | | | 567 | |
565 | /* Program each queue's start addr, cur addr, and len registers | | 568 | /* Program each queue's start addr, cur addr, and len registers |
566 | * with the physical addresses. | | 569 | * with the physical addresses. |
567 | */ | | 570 | */ |
568 | CEMAC_WRITE(ETH_RBQP, (uint32_t)sc->rbqpage_dsaddr); | | 571 | CEMAC_WRITE(ETH_RBQP, (uint32_t)sc->rbqpage_dsaddr); |
569 | CEMAC_WRITE(ETH_TBQP, (uint32_t)sc->tbqpage_dsaddr); | | 572 | CEMAC_WRITE(ETH_TBQP, (uint32_t)sc->tbqpage_dsaddr); |
570 | | | 573 | |
571 | /* Divide HCLK by 32 for MDC clock */ | | 574 | /* Divide HCLK by 32 for MDC clock */ |
572 | sc->sc_ethercom.ec_mii = mii; | | 575 | sc->sc_ethercom.ec_mii = mii; |
573 | mii->mii_ifp = ifp; | | 576 | mii->mii_ifp = ifp; |
574 | mii->mii_readreg = cemac_mii_readreg; | | 577 | mii->mii_readreg = cemac_mii_readreg; |
575 | mii->mii_writereg = cemac_mii_writereg; | | 578 | mii->mii_writereg = cemac_mii_writereg; |
576 | mii->mii_statchg = cemac_statchg; | | 579 | mii->mii_statchg = cemac_statchg; |
577 | ifmedia_init(&mii->mii_media, IFM_IMASK, cemac_mediachange, | | 580 | ifmedia_init(&mii->mii_media, IFM_IMASK, cemac_mediachange, |
578 | cemac_mediastatus); | | 581 | cemac_mediastatus); |
579 | mii_attach(sc->sc_dev, mii, 0xffffffff, MII_PHY_ANY, | | 582 | mii_attach(sc->sc_dev, mii, 0xffffffff, MII_PHY_ANY, |
580 | MII_OFFSET_ANY, 0); | | 583 | MII_OFFSET_ANY, 0); |
581 | ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_AUTO); | | 584 | ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_AUTO); |
582 | | | 585 | |
583 | #if 0 | | 586 | #if 0 |
584 | // enable / disable interrupts | | 587 | // enable / disable interrupts |
585 | CEMAC_WRITE(ETH_IDR, -1); | | 588 | CEMAC_WRITE(ETH_IDR, -1); |
586 | CEMAC_WRITE(ETH_IER, ETH_ISR_RCOM | ETH_ISR_TBRE | ETH_ISR_TIDLE | | 589 | CEMAC_WRITE(ETH_IER, ETH_ISR_RCOM | ETH_ISR_TBRE | ETH_ISR_TIDLE |
587 | | ETH_ISR_RBNA | ETH_ISR_ROVR | ETH_ISR_TCOM); | | 590 | | ETH_ISR_RBNA | ETH_ISR_ROVR | ETH_ISR_TCOM); |
588 | // (void)CEMAC_READ(ETH_ISR); // why | | 591 | // (void)CEMAC_READ(ETH_ISR); // why |
589 | | | 592 | |
590 | // enable transmitter / receiver | | 593 | // enable transmitter / receiver |
591 | CEMAC_WRITE(ETH_CTL, ETH_CTL_TE | ETH_CTL_RE | ETH_CTL_ISR | | 594 | CEMAC_WRITE(ETH_CTL, ETH_CTL_TE | ETH_CTL_RE | ETH_CTL_ISR |
592 | | ETH_CTL_CSR | ETH_CTL_MPE); | | 595 | | ETH_CTL_CSR | ETH_CTL_MPE); |
593 | #endif | | 596 | #endif |
594 | /* | | 597 | /* |
595 | * We can support hardware checksumming. | | 598 | * We can support hardware checksumming. |
596 | */ | | 599 | */ |
597 | ifp->if_capabilities |= | | 600 | ifp->if_capabilities |= |
598 | IFCAP_CSUM_IPv4_Tx | IFCAP_CSUM_IPv4_Rx | | | 601 | IFCAP_CSUM_IPv4_Tx | IFCAP_CSUM_IPv4_Rx | |
599 | IFCAP_CSUM_TCPv4_Tx | IFCAP_CSUM_TCPv4_Rx | | | 602 | IFCAP_CSUM_TCPv4_Tx | IFCAP_CSUM_TCPv4_Rx | |
600 | IFCAP_CSUM_UDPv4_Tx | IFCAP_CSUM_UDPv4_Rx | | | 603 | IFCAP_CSUM_UDPv4_Tx | IFCAP_CSUM_UDPv4_Rx | |
601 | IFCAP_CSUM_TCPv6_Tx | IFCAP_CSUM_TCPv6_Rx | | | 604 | IFCAP_CSUM_TCPv6_Tx | IFCAP_CSUM_TCPv6_Rx | |
602 | IFCAP_CSUM_UDPv6_Tx | IFCAP_CSUM_UDPv6_Rx; | | 605 | IFCAP_CSUM_UDPv6_Tx | IFCAP_CSUM_UDPv6_Rx; |
603 | | | 606 | |
604 | /* | | 607 | /* |
605 | * We can support 802.1Q VLAN-sized frames. | | 608 | * We can support 802.1Q VLAN-sized frames. |
606 | */ | | 609 | */ |
607 | sc->sc_ethercom.ec_capabilities |= ETHERCAP_VLAN_MTU; | | 610 | sc->sc_ethercom.ec_capabilities |= ETHERCAP_VLAN_MTU; |
608 | | | 611 | |
609 | strcpy(ifp->if_xname, device_xname(sc->sc_dev)); | | 612 | strcpy(ifp->if_xname, device_xname(sc->sc_dev)); |
610 | ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; | | 613 | ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; |
611 | ifp->if_ioctl = cemac_ifioctl; | | 614 | ifp->if_ioctl = cemac_ifioctl; |
612 | ifp->if_start = cemac_ifstart; | | 615 | ifp->if_start = cemac_ifstart; |
613 | ifp->if_watchdog = cemac_ifwatchdog; | | 616 | ifp->if_watchdog = cemac_ifwatchdog; |
614 | ifp->if_init = cemac_ifinit; | | 617 | ifp->if_init = cemac_ifinit; |
615 | ifp->if_stop = cemac_ifstop; | | 618 | ifp->if_stop = cemac_ifstop; |
616 | ifp->if_timer = 0; | | 619 | ifp->if_timer = 0; |
617 | ifp->if_softc = sc; | | 620 | ifp->if_softc = sc; |
618 | IFQ_SET_READY(&ifp->if_snd); | | 621 | IFQ_SET_READY(&ifp->if_snd); |
619 | if_attach(ifp); | | 622 | if_attach(ifp); |
620 | if_deferred_start_init(ifp, NULL); | | 623 | if_deferred_start_init(ifp, NULL); |
621 | ether_ifattach(ifp, (sc)->sc_enaddr); | | 624 | ether_ifattach(ifp, (sc)->sc_enaddr); |
622 | } | | 625 | } |
623 | | | 626 | |
624 | static int | | 627 | static int |
625 | cemac_mediachange(struct ifnet *ifp) | | 628 | cemac_mediachange(struct ifnet *ifp) |
626 | { | | 629 | { |
627 | if (ifp->if_flags & IFF_UP) | | 630 | if (ifp->if_flags & IFF_UP) |
628 | cemac_ifinit(ifp); | | 631 | cemac_ifinit(ifp); |
629 | return (0); | | 632 | return (0); |
630 | } | | 633 | } |
631 | | | 634 | |
632 | static void | | 635 | static void |
633 | cemac_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr) | | 636 | cemac_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr) |
634 | { | | 637 | { |
635 | struct cemac_softc *sc = ifp->if_softc; | | 638 | struct cemac_softc *sc = ifp->if_softc; |
636 | | | 639 | |
637 | mii_pollstat(&sc->sc_mii); | | 640 | mii_pollstat(&sc->sc_mii); |
638 | ifmr->ifm_active = sc->sc_mii.mii_media_active; | | 641 | ifmr->ifm_active = sc->sc_mii.mii_media_active; |
639 | ifmr->ifm_status = sc->sc_mii.mii_media_status; | | 642 | ifmr->ifm_status = sc->sc_mii.mii_media_status; |
640 | } | | 643 | } |
641 | | | 644 | |
642 | | | 645 | |
643 | static int | | 646 | static int |
644 | cemac_mii_readreg(device_t self, int phy, int reg, uint16_t *val) | | 647 | cemac_mii_readreg(device_t self, int phy, int reg, uint16_t *val) |
645 | { | | 648 | { |
646 | struct cemac_softc *sc; | | 649 | struct cemac_softc *sc; |
647 | | | 650 | |
648 | sc = device_private(self); | | 651 | sc = device_private(self); |
649 | | | 652 | |
650 | CEMAC_WRITE(ETH_MAN, (ETH_MAN_HIGH | ETH_MAN_RW_RD | | 653 | CEMAC_WRITE(ETH_MAN, (ETH_MAN_HIGH | ETH_MAN_RW_RD |
651 | | ((phy << ETH_MAN_PHYA_SHIFT) & ETH_MAN_PHYA) | | 654 | | ((phy << ETH_MAN_PHYA_SHIFT) & ETH_MAN_PHYA) |
652 | | ((reg << ETH_MAN_REGA_SHIFT) & ETH_MAN_REGA) | | 655 | | ((reg << ETH_MAN_REGA_SHIFT) & ETH_MAN_REGA) |
653 | | ETH_MAN_CODE_IEEE802_3)); | | 656 | | ETH_MAN_CODE_IEEE802_3)); |
654 | while (!(CEMAC_READ(ETH_SR) & ETH_SR_IDLE)) | | 657 | while (!(CEMAC_READ(ETH_SR) & ETH_SR_IDLE)) |
655 | ; | | 658 | ; |
656 | | | 659 | |
657 | *val = CEMAC_READ(ETH_MAN) & ETH_MAN_DATA; | | 660 | *val = CEMAC_READ(ETH_MAN) & ETH_MAN_DATA; |
658 | return 0; | | 661 | return 0; |
659 | } | | 662 | } |
660 | | | 663 | |
661 | static int | | 664 | static int |
662 | cemac_mii_writereg(device_t self, int phy, int reg, uint16_t val) | | 665 | cemac_mii_writereg(device_t self, int phy, int reg, uint16_t val) |
663 | { | | 666 | { |
664 | struct cemac_softc *sc; | | 667 | struct cemac_softc *sc; |
665 | | | 668 | |
666 | sc = device_private(self); | | 669 | sc = device_private(self); |
667 | | | 670 | |
668 | CEMAC_WRITE(ETH_MAN, (ETH_MAN_HIGH | ETH_MAN_RW_WR | | 671 | CEMAC_WRITE(ETH_MAN, (ETH_MAN_HIGH | ETH_MAN_RW_WR |
669 | | ((phy << ETH_MAN_PHYA_SHIFT) & ETH_MAN_PHYA) | | 672 | | ((phy << ETH_MAN_PHYA_SHIFT) & ETH_MAN_PHYA) |
670 | | ((reg << ETH_MAN_REGA_SHIFT) & ETH_MAN_REGA) | | 673 | | ((reg << ETH_MAN_REGA_SHIFT) & ETH_MAN_REGA) |
671 | | ETH_MAN_CODE_IEEE802_3 | | 674 | | ETH_MAN_CODE_IEEE802_3 |
672 | | (val & ETH_MAN_DATA))); | | 675 | | (val & ETH_MAN_DATA))); |
673 | while (!(CEMAC_READ(ETH_SR) & ETH_SR_IDLE)) | | 676 | while (!(CEMAC_READ(ETH_SR) & ETH_SR_IDLE)) |
674 | ; | | 677 | ; |
675 | | | 678 | |
676 | return 0; | | 679 | return 0; |
677 | } | | 680 | } |
678 | | | 681 | |
679 | | | 682 | |
680 | static void | | 683 | static void |
681 | cemac_statchg(struct ifnet *ifp) | | 684 | cemac_statchg(struct ifnet *ifp) |
682 | { | | 685 | { |
683 | struct cemac_softc *sc = ifp->if_softc; | | 686 | struct cemac_softc *sc = ifp->if_softc; |
684 | struct mii_data *mii = &sc->sc_mii; | | 687 | struct mii_data *mii = &sc->sc_mii; |
685 | uint32_t reg; | | 688 | uint32_t reg; |
686 | | | 689 | |
687 | /* | | 690 | /* |
688 | * We must keep the MAC and the PHY in sync as | | 691 | * We must keep the MAC and the PHY in sync as |
689 | * to the status of full-duplex! | | 692 | * to the status of full-duplex! |
690 | */ | | 693 | */ |
691 | reg = CEMAC_READ(ETH_CFG); | | 694 | reg = CEMAC_READ(ETH_CFG); |
692 | reg &= ~ETH_CFG_FD; | | 695 | reg &= ~ETH_CFG_FD; |
693 | if (sc->sc_mii.mii_media_active & IFM_FDX) | | 696 | if (sc->sc_mii.mii_media_active & IFM_FDX) |
694 | reg |= ETH_CFG_FD; | | 697 | reg |= ETH_CFG_FD; |
695 | | | 698 | |
696 | reg &= ~ETH_CFG_SPD; | | 699 | reg &= ~ETH_CFG_SPD; |
697 | if (ISSET(sc->cemac_flags, CEMAC_FLAG_GEM)) | | 700 | if (ISSET(sc->cemac_flags, CEMAC_FLAG_GEM)) |
698 | reg &= ~GEM_CFG_GEN; | | 701 | reg &= ~GEM_CFG_GEN; |
699 | switch (IFM_SUBTYPE(mii->mii_media_active)) { | | 702 | switch (IFM_SUBTYPE(mii->mii_media_active)) { |
700 | case IFM_10_T: | | 703 | case IFM_10_T: |
701 | break; | | 704 | break; |
702 | case IFM_100_TX: | | 705 | case IFM_100_TX: |
703 | reg |= ETH_CFG_SPD; | | 706 | reg |= ETH_CFG_SPD; |
704 | break; | | 707 | break; |
705 | case IFM_1000_T: | | 708 | case IFM_1000_T: |
706 | reg |= ETH_CFG_SPD | GEM_CFG_GEN; | | 709 | reg |= ETH_CFG_SPD | GEM_CFG_GEN; |
707 | break; | | 710 | break; |
708 | default: | | 711 | default: |
709 | break; | | 712 | break; |
710 | } | | 713 | } |
711 | CEMAC_WRITE(ETH_CFG, reg); | | 714 | CEMAC_WRITE(ETH_CFG, reg); |
712 | } | | 715 | } |
713 | | | 716 | |
714 | static void | | 717 | static void |
715 | cemac_tick(void *arg) | | 718 | cemac_tick(void *arg) |
716 | { | | 719 | { |
717 | struct cemac_softc* sc = (struct cemac_softc *)arg; | | 720 | struct cemac_softc* sc = (struct cemac_softc *)arg; |
718 | struct ifnet * ifp = &sc->sc_ethercom.ec_if; | | 721 | struct ifnet * ifp = &sc->sc_ethercom.ec_if; |
719 | int s; | | 722 | int s; |
720 | | | 723 | |
721 | if (ISSET(sc->cemac_flags, CEMAC_FLAG_GEM)) | | 724 | if (ISSET(sc->cemac_flags, CEMAC_FLAG_GEM)) |
722 | ifp->if_collisions += CEMAC_READ(GEM_SCOL) + CEMAC_READ(GEM_MCOL); | | 725 | if_statadd(ifp, if_collisions, |
| | | 726 | CEMAC_READ(GEM_SCOL) + CEMAC_READ(GEM_MCOL)); |
723 | else | | 727 | else |
724 | ifp->if_collisions += CEMAC_READ(ETH_SCOL) + CEMAC_READ(ETH_MCOL); | | 728 | if_statadd(ifp, if_collisions, |
| | | 729 | CEMAC_READ(ETH_SCOL) + CEMAC_READ(ETH_MCOL)); |
725 | | | 730 | |
726 | /* These misses are ok, they will happen if the RAM/CPU can't keep up */ | | 731 | /* These misses are ok, they will happen if the RAM/CPU can't keep up */ |
727 | if (!ISSET(sc->cemac_flags, CEMAC_FLAG_GEM)) { | | 732 | if (!ISSET(sc->cemac_flags, CEMAC_FLAG_GEM)) { |
728 | uint32_t misses = CEMAC_READ(ETH_DRFC); | | 733 | uint32_t misses = CEMAC_READ(ETH_DRFC); |
729 | if (misses > 0) | | 734 | if (misses > 0) |
730 | aprint_normal_ifnet(ifp, "%d rx misses\n", misses); | | 735 | aprint_normal_ifnet(ifp, "%d rx misses\n", misses); |
731 | } | | 736 | } |
732 | | | 737 | |
733 | s = splnet(); | | 738 | s = splnet(); |
734 | if (cemac_gctx(sc) > 0 && IFQ_IS_EMPTY(&ifp->if_snd) == 0) | | 739 | if (cemac_gctx(sc) > 0 && IFQ_IS_EMPTY(&ifp->if_snd) == 0) |
735 | cemac_ifstart(ifp); | | 740 | cemac_ifstart(ifp); |
736 | splx(s); | | 741 | splx(s); |
737 | | | 742 | |
738 | mii_tick(&sc->sc_mii); | | 743 | mii_tick(&sc->sc_mii); |
739 | callout_reset(&sc->cemac_tick_ch, hz, cemac_tick, sc); | | 744 | callout_reset(&sc->cemac_tick_ch, hz, cemac_tick, sc); |
740 | } | | 745 | } |
741 | | | 746 | |
742 | | | 747 | |
743 | static int | | 748 | static int |
744 | cemac_ifioctl(struct ifnet *ifp, u_long cmd, void *data) | | 749 | cemac_ifioctl(struct ifnet *ifp, u_long cmd, void *data) |
745 | { | | 750 | { |
746 | int s, error; | | 751 | int s, error; |
747 | | | 752 | |
748 | s = splnet(); | | 753 | s = splnet(); |
749 | switch (cmd) { | | 754 | switch (cmd) { |
750 | default: | | 755 | default: |
751 | error = ether_ioctl(ifp, cmd, data); | | 756 | error = ether_ioctl(ifp, cmd, data); |
752 | if (error != ENETRESET) | | 757 | if (error != ENETRESET) |
753 | break; | | 758 | break; |
754 | error = 0; | | 759 | error = 0; |
755 | | | 760 | |
756 | if (cmd == SIOCSIFCAP) { | | 761 | if (cmd == SIOCSIFCAP) { |
757 | error = (*ifp->if_init)(ifp); | | 762 | error = (*ifp->if_init)(ifp); |
758 | } else if (cmd != SIOCADDMULTI && cmd != SIOCDELMULTI) | | 763 | } else if (cmd != SIOCADDMULTI && cmd != SIOCDELMULTI) |
759 | ; | | 764 | ; |
760 | else if (ifp->if_flags & IFF_RUNNING) { | | 765 | else if (ifp->if_flags & IFF_RUNNING) { |
761 | cemac_setaddr(ifp); | | 766 | cemac_setaddr(ifp); |
762 | } | | 767 | } |
763 | } | | 768 | } |
764 | splx(s); | | 769 | splx(s); |
765 | return error; | | 770 | return error; |
766 | } | | 771 | } |
767 | | | 772 | |
768 | static void | | 773 | static void |
769 | cemac_ifstart(struct ifnet *ifp) | | 774 | cemac_ifstart(struct ifnet *ifp) |
770 | { | | 775 | { |
771 | struct cemac_softc *sc = (struct cemac_softc *)ifp->if_softc; | | 776 | struct cemac_softc *sc = (struct cemac_softc *)ifp->if_softc; |
772 | struct mbuf *m; | | 777 | struct mbuf *m; |
773 | bus_dma_segment_t *segs; | | 778 | bus_dma_segment_t *segs; |
774 | int s, bi, err, nsegs; | | 779 | int s, bi, err, nsegs; |
775 | | | 780 | |
776 | s = splnet(); | | 781 | s = splnet(); |
777 | start: | | 782 | start: |
778 | if (cemac_gctx(sc) == 0) { | | 783 | if (cemac_gctx(sc) == 0) { |
779 | /* Enable transmit-buffer-free interrupt */ | | 784 | /* Enable transmit-buffer-free interrupt */ |
780 | CEMAC_WRITE(ETH_IER, ETH_ISR_TBRE); | | 785 | CEMAC_WRITE(ETH_IER, ETH_ISR_TBRE); |
781 | ifp->if_flags |= IFF_OACTIVE; | | 786 | ifp->if_flags |= IFF_OACTIVE; |
782 | ifp->if_timer = 10; | | 787 | ifp->if_timer = 10; |
783 | splx(s); | | 788 | splx(s); |
784 | return; | | 789 | return; |
785 | } | | 790 | } |
786 | | | 791 | |
787 | ifp->if_timer = 0; | | 792 | ifp->if_timer = 0; |
788 | | | 793 | |
789 | IFQ_POLL(&ifp->if_snd, m); | | 794 | IFQ_POLL(&ifp->if_snd, m); |
790 | if (m == NULL) { | | 795 | if (m == NULL) { |
791 | splx(s); | | 796 | splx(s); |
792 | return; | | 797 | return; |
793 | } | | 798 | } |
794 | | | 799 | |
795 | bi = (sc->txqi + sc->txqc) % TX_QLEN; | | 800 | bi = (sc->txqi + sc->txqc) % TX_QLEN; |
796 | if ((err = bus_dmamap_load_mbuf(sc->sc_dmat, sc->txq[bi].m_dmamap, m, | | 801 | if ((err = bus_dmamap_load_mbuf(sc->sc_dmat, sc->txq[bi].m_dmamap, m, |
797 | BUS_DMA_NOWAIT)) || | | 802 | BUS_DMA_NOWAIT)) || |
798 | sc->txq[bi].m_dmamap->dm_segs[0].ds_addr & 0x3 || | | 803 | sc->txq[bi].m_dmamap->dm_segs[0].ds_addr & 0x3 || |
799 | sc->txq[bi].m_dmamap->dm_nsegs > 1) { | | 804 | sc->txq[bi].m_dmamap->dm_nsegs > 1) { |
800 | /* Copy entire mbuf chain to new single */ | | 805 | /* Copy entire mbuf chain to new single */ |
801 | struct mbuf *mn; | | 806 | struct mbuf *mn; |
802 | | | 807 | |
803 | if (err == 0) | | 808 | if (err == 0) |
804 | bus_dmamap_unload(sc->sc_dmat, sc->txq[bi].m_dmamap); | | 809 | bus_dmamap_unload(sc->sc_dmat, sc->txq[bi].m_dmamap); |
805 | | | 810 | |
806 | MGETHDR(mn, M_DONTWAIT, MT_DATA); | | 811 | MGETHDR(mn, M_DONTWAIT, MT_DATA); |
807 | if (mn == NULL) goto stop; | | 812 | if (mn == NULL) goto stop; |
808 | if (m->m_pkthdr.len > MHLEN) { | | 813 | if (m->m_pkthdr.len > MHLEN) { |
809 | MCLGET(mn, M_DONTWAIT); | | 814 | MCLGET(mn, M_DONTWAIT); |
810 | if ((mn->m_flags & M_EXT) == 0) { | | 815 | if ((mn->m_flags & M_EXT) == 0) { |
811 | m_freem(mn); | | 816 | m_freem(mn); |
812 | goto stop; | | 817 | goto stop; |
813 | } | | 818 | } |
814 | } | | 819 | } |
815 | m_copydata(m, 0, m->m_pkthdr.len, mtod(mn, void *)); | | 820 | m_copydata(m, 0, m->m_pkthdr.len, mtod(mn, void *)); |
816 | mn->m_pkthdr.len = mn->m_len = m->m_pkthdr.len; | | 821 | mn->m_pkthdr.len = mn->m_len = m->m_pkthdr.len; |
817 | IFQ_DEQUEUE(&ifp->if_snd, m); | | 822 | IFQ_DEQUEUE(&ifp->if_snd, m); |
818 | m_freem(m); | | 823 | m_freem(m); |
819 | m = mn; | | 824 | m = mn; |
820 | bus_dmamap_load_mbuf(sc->sc_dmat, sc->txq[bi].m_dmamap, m, | | 825 | bus_dmamap_load_mbuf(sc->sc_dmat, sc->txq[bi].m_dmamap, m, |
821 | BUS_DMA_NOWAIT); | | 826 | BUS_DMA_NOWAIT); |
822 | } else { | | 827 | } else { |
823 | IFQ_DEQUEUE(&ifp->if_snd, m); | | 828 | IFQ_DEQUEUE(&ifp->if_snd, m); |
824 | } | | 829 | } |
825 | | | 830 | |
826 | bpf_mtap(ifp, m, BPF_D_OUT); | | 831 | bpf_mtap(ifp, m, BPF_D_OUT); |
827 | | | 832 | |
828 | nsegs = sc->txq[bi].m_dmamap->dm_nsegs; | | 833 | nsegs = sc->txq[bi].m_dmamap->dm_nsegs; |
829 | segs = sc->txq[bi].m_dmamap->dm_segs; | | 834 | segs = sc->txq[bi].m_dmamap->dm_segs; |
830 | if (nsegs > 1) | | 835 | if (nsegs > 1) |
831 | panic("#### ARGH #2"); | | 836 | panic("#### ARGH #2"); |
832 | | | 837 | |
833 | sc->txq[bi].m = m; | | 838 | sc->txq[bi].m = m; |
834 | sc->txqc++; | | 839 | sc->txqc++; |
835 | | | 840 | |
836 | DPRINTFN(2,("%s: start sending idx #%i mbuf %p (txqc=%i, phys %p), len=%u\n", | | 841 | DPRINTFN(2,("%s: start sending idx #%i mbuf %p (txqc=%i, phys %p), len=%u\n", |
837 | __FUNCTION__, bi, sc->txq[bi].m, sc->txqc, (void*)segs->ds_addr, | | 842 | __FUNCTION__, bi, sc->txq[bi].m, sc->txqc, (void*)segs->ds_addr, |
838 | (unsigned)m->m_pkthdr.len)); | | 843 | (unsigned)m->m_pkthdr.len)); |
839 | #ifdef DIAGNOSTIC | | 844 | #ifdef DIAGNOSTIC |
840 | if (sc->txqc > TX_QLEN) | | 845 | if (sc->txqc > TX_QLEN) |
841 | panic("%s: txqc %i > %i", __FUNCTION__, sc->txqc, TX_QLEN); | | 846 | panic("%s: txqc %i > %i", __FUNCTION__, sc->txqc, TX_QLEN); |
842 | #endif | | 847 | #endif |
843 | | | 848 | |
844 | bus_dmamap_sync(sc->sc_dmat, sc->txq[bi].m_dmamap, 0, | | 849 | bus_dmamap_sync(sc->sc_dmat, sc->txq[bi].m_dmamap, 0, |
845 | sc->txq[bi].m_dmamap->dm_mapsize, | | 850 | sc->txq[bi].m_dmamap->dm_mapsize, |
846 | BUS_DMASYNC_PREWRITE); | | 851 | BUS_DMASYNC_PREWRITE); |
847 | | | 852 | |
848 | if (ISSET(sc->cemac_flags, CEMAC_FLAG_GEM)) { | | 853 | if (ISSET(sc->cemac_flags, CEMAC_FLAG_GEM)) { |
849 | sc->TDSC[bi].Addr = segs->ds_addr; | | 854 | sc->TDSC[bi].Addr = segs->ds_addr; |
850 | sc->TDSC[bi].Info = __SHIFTIN(m->m_pkthdr.len, ETH_TDSC_I_LEN) | | | 855 | sc->TDSC[bi].Info = __SHIFTIN(m->m_pkthdr.len, ETH_TDSC_I_LEN) | |
851 | ETH_TDSC_I_LAST_BUF | (bi == (TX_QLEN - 1) ? ETH_TDSC_I_WRAP : 0); | | 856 | ETH_TDSC_I_LAST_BUF | (bi == (TX_QLEN - 1) ? ETH_TDSC_I_WRAP : 0); |
852 | | | 857 | |
853 | DPRINTFN(3,("%s: TDSC[%i].Addr 0x%08x\n", | | 858 | DPRINTFN(3,("%s: TDSC[%i].Addr 0x%08x\n", |
854 | __FUNCTION__, bi, sc->TDSC[bi].Addr)); | | 859 | __FUNCTION__, bi, sc->TDSC[bi].Addr)); |
855 | DPRINTFN(3,("%s: TDSC[%i].Info 0x%08x\n", | | 860 | DPRINTFN(3,("%s: TDSC[%i].Info 0x%08x\n", |
856 | __FUNCTION__, bi, sc->TDSC[bi].Info)); | | 861 | __FUNCTION__, bi, sc->TDSC[bi].Info)); |
857 | | | 862 | |
858 | uint32_t ctl = CEMAC_READ(ETH_CTL) | GEM_CTL_STARTTX; | | 863 | uint32_t ctl = CEMAC_READ(ETH_CTL) | GEM_CTL_STARTTX; |
859 | CEMAC_WRITE(ETH_CTL, ctl); | | 864 | CEMAC_WRITE(ETH_CTL, ctl); |
860 | DPRINTFN(3,("%s: ETH_CTL 0x%08x\n", __FUNCTION__, CEMAC_READ(ETH_CTL))); | | 865 | DPRINTFN(3,("%s: ETH_CTL 0x%08x\n", __FUNCTION__, CEMAC_READ(ETH_CTL))); |
861 | } else { | | 866 | } else { |
862 | CEMAC_WRITE(ETH_TAR, segs->ds_addr); | | 867 | CEMAC_WRITE(ETH_TAR, segs->ds_addr); |
863 | CEMAC_WRITE(ETH_TCR, m->m_pkthdr.len); | | 868 | CEMAC_WRITE(ETH_TCR, m->m_pkthdr.len); |
864 | } | | 869 | } |
865 | if (IFQ_IS_EMPTY(&ifp->if_snd) == 0) | | 870 | if (IFQ_IS_EMPTY(&ifp->if_snd) == 0) |
866 | goto start; | | 871 | goto start; |
867 | stop: | | 872 | stop: |
868 | | | 873 | |
869 | splx(s); | | 874 | splx(s); |
870 | return; | | 875 | return; |
871 | } | | 876 | } |
872 | | | 877 | |
873 | static void | | 878 | static void |
874 | cemac_ifwatchdog(struct ifnet *ifp) | | 879 | cemac_ifwatchdog(struct ifnet *ifp) |
875 | { | | 880 | { |
876 | struct cemac_softc *sc = (struct cemac_softc *)ifp->if_softc; | | 881 | struct cemac_softc *sc = (struct cemac_softc *)ifp->if_softc; |
877 | | | 882 | |
878 | if ((ifp->if_flags & IFF_RUNNING) == 0) | | 883 | if ((ifp->if_flags & IFF_RUNNING) == 0) |
879 | return; | | 884 | return; |
880 | aprint_error_ifnet(ifp, "device timeout, CTL = 0x%08x, CFG = 0x%08x\n", | | 885 | aprint_error_ifnet(ifp, "device timeout, CTL = 0x%08x, CFG = 0x%08x\n", |
881 | CEMAC_READ(ETH_CTL), CEMAC_READ(ETH_CFG)); | | 886 | CEMAC_READ(ETH_CTL), CEMAC_READ(ETH_CFG)); |
882 | } | | 887 | } |
883 | | | 888 | |
884 | static int | | 889 | static int |
885 | cemac_ifinit(struct ifnet *ifp) | | 890 | cemac_ifinit(struct ifnet *ifp) |
886 | { | | 891 | { |
887 | struct cemac_softc *sc = ifp->if_softc; | | 892 | struct cemac_softc *sc = ifp->if_softc; |
888 | uint32_t dma, cfg; | | 893 | uint32_t dma, cfg; |
889 | int s = splnet(); | | 894 | int s = splnet(); |
890 | | | 895 | |
891 | callout_stop(&sc->cemac_tick_ch); | | 896 | callout_stop(&sc->cemac_tick_ch); |
892 | | | 897 | |
893 | if (ISSET(sc->cemac_flags, CEMAC_FLAG_GEM)) { | | 898 | if (ISSET(sc->cemac_flags, CEMAC_FLAG_GEM)) { |
894 | | | 899 | |
895 | if (ifp->if_capenable & | | 900 | if (ifp->if_capenable & |
896 | (IFCAP_CSUM_IPv4_Tx | | | 901 | (IFCAP_CSUM_IPv4_Tx | |
897 | IFCAP_CSUM_TCPv4_Tx | IFCAP_CSUM_UDPv4_Tx | | | 902 | IFCAP_CSUM_TCPv4_Tx | IFCAP_CSUM_UDPv4_Tx | |
898 | IFCAP_CSUM_TCPv6_Tx | IFCAP_CSUM_UDPv6_Tx)) { | | 903 | IFCAP_CSUM_TCPv6_Tx | IFCAP_CSUM_UDPv6_Tx)) { |
899 | dma = CEMAC_READ(GEM_DMA_CFG); | | 904 | dma = CEMAC_READ(GEM_DMA_CFG); |
900 | dma |= GEM_DMA_CFG_CHKSUM_GEN_OFFLOAD_EN; | | 905 | dma |= GEM_DMA_CFG_CHKSUM_GEN_OFFLOAD_EN; |
901 | CEMAC_WRITE(GEM_DMA_CFG, dma); | | 906 | CEMAC_WRITE(GEM_DMA_CFG, dma); |
902 | } | | 907 | } |
903 | if (ifp->if_capenable & | | 908 | if (ifp->if_capenable & |
904 | (IFCAP_CSUM_IPv4_Rx | | | 909 | (IFCAP_CSUM_IPv4_Rx | |
905 | IFCAP_CSUM_TCPv4_Rx | IFCAP_CSUM_UDPv4_Rx | | | 910 | IFCAP_CSUM_TCPv4_Rx | IFCAP_CSUM_UDPv4_Rx | |
906 | IFCAP_CSUM_TCPv6_Rx | IFCAP_CSUM_UDPv6_Rx)) { | | 911 | IFCAP_CSUM_TCPv6_Rx | IFCAP_CSUM_UDPv6_Rx)) { |
907 | cfg = CEMAC_READ(ETH_CFG); | | 912 | cfg = CEMAC_READ(ETH_CFG); |
908 | cfg |= GEM_CFG_RX_CHKSUM_OFFLD_EN; | | 913 | cfg |= GEM_CFG_RX_CHKSUM_OFFLD_EN; |
909 | CEMAC_WRITE(ETH_CFG, cfg); | | 914 | CEMAC_WRITE(ETH_CFG, cfg); |
910 | } | | 915 | } |
911 | } | | 916 | } |
912 | | | 917 | |
913 | // enable interrupts | | 918 | // enable interrupts |
914 | CEMAC_WRITE(ETH_IDR, -1); | | 919 | CEMAC_WRITE(ETH_IDR, -1); |
915 | CEMAC_WRITE(ETH_IER, ETH_ISR_RCOM | ETH_ISR_TBRE | ETH_ISR_TIDLE | | 920 | CEMAC_WRITE(ETH_IER, ETH_ISR_RCOM | ETH_ISR_TBRE | ETH_ISR_TIDLE |
916 | | ETH_ISR_RBNA | ETH_ISR_ROVR | ETH_ISR_TCOM); | | 921 | | ETH_ISR_RBNA | ETH_ISR_ROVR | ETH_ISR_TCOM); |
917 | | | 922 | |
918 | // enable transmitter / receiver | | 923 | // enable transmitter / receiver |
919 | CEMAC_WRITE(ETH_CTL, ETH_CTL_TE | ETH_CTL_RE | ETH_CTL_ISR | | 924 | CEMAC_WRITE(ETH_CTL, ETH_CTL_TE | ETH_CTL_RE | ETH_CTL_ISR |
920 | | ETH_CTL_CSR | ETH_CTL_MPE); | | 925 | | ETH_CTL_CSR | ETH_CTL_MPE); |
921 | | | 926 | |
922 | mii_mediachg(&sc->sc_mii); | | 927 | mii_mediachg(&sc->sc_mii); |
923 | callout_reset(&sc->cemac_tick_ch, hz, cemac_tick, sc); | | 928 | callout_reset(&sc->cemac_tick_ch, hz, cemac_tick, sc); |
924 | ifp->if_flags |= IFF_RUNNING; | | 929 | ifp->if_flags |= IFF_RUNNING; |
925 | splx(s); | | 930 | splx(s); |
926 | return 0; | | 931 | return 0; |
927 | } | | 932 | } |
928 | | | 933 | |
929 | static void | | 934 | static void |
930 | cemac_ifstop(struct ifnet *ifp, int disable) | | 935 | cemac_ifstop(struct ifnet *ifp, int disable) |
931 | { | | 936 | { |
932 | // uint32_t u; | | 937 | // uint32_t u; |
933 | struct cemac_softc *sc = ifp->if_softc; | | 938 | struct cemac_softc *sc = ifp->if_softc; |
934 | | | 939 | |
935 | #if 0 | | 940 | #if 0 |
936 | CEMAC_WRITE(ETH_CTL, ETH_CTL_MPE); // disable everything | | 941 | CEMAC_WRITE(ETH_CTL, ETH_CTL_MPE); // disable everything |
937 | CEMAC_WRITE(ETH_IDR, -1); // disable interrupts | | 942 | CEMAC_WRITE(ETH_IDR, -1); // disable interrupts |
938 | // CEMAC_WRITE(ETH_RBQP, 0); // clear receive | | 943 | // CEMAC_WRITE(ETH_RBQP, 0); // clear receive |
939 | if (ISSET(sc->cemac_flags, CEMAC_FLAG_GEM)) | | 944 | if (ISSET(sc->cemac_flags, CEMAC_FLAG_GEM)) |
940 | CEMAC_WRITE(ETH_CFG, | | 945 | CEMAC_WRITE(ETH_CFG, |
941 | GEM_CFG_CLK_64 | ETH_CFG_SPD | ETH_CFG_FD | ETH_CFG_BIG); | | 946 | GEM_CFG_CLK_64 | ETH_CFG_SPD | ETH_CFG_FD | ETH_CFG_BIG); |
942 | else | | 947 | else |
943 | CEMAC_WRITE(ETH_CFG, | | 948 | CEMAC_WRITE(ETH_CFG, |
944 | ETH_CFG_CLK_32 | ETH_CFG_SPD | ETH_CFG_FD | ETH_CFG_BIG); | | 949 | ETH_CFG_CLK_32 | ETH_CFG_SPD | ETH_CFG_FD | ETH_CFG_BIG); |
945 | // CEMAC_WRITE(ETH_TCR, 0); // send nothing | | 950 | // CEMAC_WRITE(ETH_TCR, 0); // send nothing |
946 | // (void)CEMAC_READ(ETH_ISR); | | 951 | // (void)CEMAC_READ(ETH_ISR); |
947 | u = CEMAC_READ(ETH_TSR); | | 952 | u = CEMAC_READ(ETH_TSR); |
948 | CEMAC_WRITE(ETH_TSR, (u & (ETH_TSR_UND | ETH_TSR_COMP | ETH_TSR_BNQ | | 953 | CEMAC_WRITE(ETH_TSR, (u & (ETH_TSR_UND | ETH_TSR_COMP | ETH_TSR_BNQ |
949 | | ETH_TSR_IDLE | ETH_TSR_RLE | | 954 | | ETH_TSR_IDLE | ETH_TSR_RLE |
950 | | ETH_TSR_COL | ETH_TSR_OVR))); | | 955 | | ETH_TSR_COL | ETH_TSR_OVR))); |
951 | u = CEMAC_READ(ETH_RSR); | | 956 | u = CEMAC_READ(ETH_RSR); |
952 | CEMAC_WRITE(ETH_RSR, (u & (ETH_RSR_OVR | ETH_RSR_REC | ETH_RSR_BNA))); | | 957 | CEMAC_WRITE(ETH_RSR, (u & (ETH_RSR_OVR | ETH_RSR_REC | ETH_RSR_BNA))); |
953 | #endif | | 958 | #endif |
954 | callout_stop(&sc->cemac_tick_ch); | | 959 | callout_stop(&sc->cemac_tick_ch); |
955 | | | 960 | |
956 | /* Down the MII. */ | | 961 | /* Down the MII. */ |
957 | mii_down(&sc->sc_mii); | | 962 | mii_down(&sc->sc_mii); |
958 | | | 963 | |
959 | ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); | | 964 | ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); |
960 | ifp->if_timer = 0; | | 965 | ifp->if_timer = 0; |
961 | sc->sc_mii.mii_media_status &= ~IFM_ACTIVE; | | 966 | sc->sc_mii.mii_media_status &= ~IFM_ACTIVE; |
962 | } | | 967 | } |
963 | | | 968 | |
964 | static void | | 969 | static void |
965 | cemac_setaddr(struct ifnet *ifp) | | 970 | cemac_setaddr(struct ifnet *ifp) |
966 | { | | 971 | { |
967 | struct cemac_softc *sc = ifp->if_softc; | | 972 | struct cemac_softc *sc = ifp->if_softc; |
968 | struct ethercom *ec = &sc->sc_ethercom; | | 973 | struct ethercom *ec = &sc->sc_ethercom; |
969 | struct ether_multi *enm; | | 974 | struct ether_multi *enm; |
970 | struct ether_multistep step; | | 975 | struct ether_multistep step; |
971 | uint8_t ias[3][ETHER_ADDR_LEN]; | | 976 | uint8_t ias[3][ETHER_ADDR_LEN]; |
972 | uint32_t h, nma = 0, hashes[2] = { 0, 0 }; | | 977 | uint32_t h, nma = 0, hashes[2] = { 0, 0 }; |
973 | uint32_t ctl = CEMAC_READ(ETH_CTL); | | 978 | uint32_t ctl = CEMAC_READ(ETH_CTL); |
974 | uint32_t cfg = CEMAC_READ(ETH_CFG); | | 979 | uint32_t cfg = CEMAC_READ(ETH_CFG); |
975 | | | 980 | |
976 | /* disable receiver temporarily */ | | 981 | /* disable receiver temporarily */ |
977 | CEMAC_WRITE(ETH_CTL, ctl & ~ETH_CTL_RE); | | 982 | CEMAC_WRITE(ETH_CTL, ctl & ~ETH_CTL_RE); |
978 | | | 983 | |
979 | cfg &= ~(ETH_CFG_MTI | ETH_CFG_UNI | ETH_CFG_CAF | ETH_CFG_UNI); | | 984 | cfg &= ~(ETH_CFG_MTI | ETH_CFG_UNI | ETH_CFG_CAF | ETH_CFG_UNI); |
980 | | | 985 | |
981 | if (ifp->if_flags & IFF_PROMISC) { | | 986 | if (ifp->if_flags & IFF_PROMISC) { |
982 | cfg |= ETH_CFG_CAF; | | 987 | cfg |= ETH_CFG_CAF; |
983 | } else { | | 988 | } else { |
984 | cfg &= ~ETH_CFG_CAF; | | 989 | cfg &= ~ETH_CFG_CAF; |
985 | } | | 990 | } |
986 | | | 991 | |
987 | // ETH_CFG_BIG? | | 992 | // ETH_CFG_BIG? |
988 | | | 993 | |
989 | ifp->if_flags &= ~IFF_ALLMULTI; | | 994 | ifp->if_flags &= ~IFF_ALLMULTI; |
990 | | | 995 | |
991 | ETHER_LOCK(ec); | | 996 | ETHER_LOCK(ec); |
992 | ETHER_FIRST_MULTI(step, ec, enm); | | 997 | ETHER_FIRST_MULTI(step, ec, enm); |
993 | while (enm != NULL) { | | 998 | while (enm != NULL) { |
994 | if (memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) { | | 999 | if (memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) { |
995 | /* | | 1000 | /* |
996 | * We must listen to a range of multicast addresses. | | 1001 | * We must listen to a range of multicast addresses. |
997 | * For now, just accept all multicasts, rather than | | 1002 | * For now, just accept all multicasts, rather than |
998 | * trying to set only those filter bits needed to match | | 1003 | * trying to set only those filter bits needed to match |
999 | * the range. (At this time, the only use of address | | 1004 | * the range. (At this time, the only use of address |
1000 | * ranges is for IP multicast routing, for which the | | 1005 | * ranges is for IP multicast routing, for which the |
1001 | * range is big enough to require all bits set.) | | 1006 | * range is big enough to require all bits set.) |
1002 | */ | | 1007 | */ |
1003 | cfg |= ETH_CFG_MTI; | | 1008 | cfg |= ETH_CFG_MTI; |
1004 | hashes[0] = 0xffffffffUL; | | 1009 | hashes[0] = 0xffffffffUL; |
1005 | hashes[1] = 0xffffffffUL; | | 1010 | hashes[1] = 0xffffffffUL; |
1006 | ifp->if_flags |= IFF_ALLMULTI; | | 1011 | ifp->if_flags |= IFF_ALLMULTI; |
1007 | nma = 0; | | 1012 | nma = 0; |
1008 | break; | | 1013 | break; |
1009 | } | | 1014 | } |
1010 | | | 1015 | |
1011 | if (nma < 3) { | | 1016 | if (nma < 3) { |
1012 | /* We can program 3 perfect address filters for mcast */ | | 1017 | /* We can program 3 perfect address filters for mcast */ |
1013 | memcpy(ias[nma], enm->enm_addrlo, ETHER_ADDR_LEN); | | 1018 | memcpy(ias[nma], enm->enm_addrlo, ETHER_ADDR_LEN); |
1014 | } else { | | 1019 | } else { |
1015 | /* | | 1020 | /* |
1016 | * XXX: Datasheet is not very clear here, I'm not sure | | 1021 | * XXX: Datasheet is not very clear here, I'm not sure |
1017 | * if I'm doing this right. --joff | | 1022 | * if I'm doing this right. --joff |
1018 | */ | | 1023 | */ |
1019 | h = ether_crc32_le(enm->enm_addrlo, ETHER_ADDR_LEN); | | 1024 | h = ether_crc32_le(enm->enm_addrlo, ETHER_ADDR_LEN); |
1020 | | | 1025 | |
1021 | /* Just want the 6 most-significant bits. */ | | 1026 | /* Just want the 6 most-significant bits. */ |
1022 | h = h >> 26; | | 1027 | h = h >> 26; |
1023 | #if 0 | | 1028 | #if 0 |
1024 | hashes[h / 32] |= (1 << (h % 32)); | | 1029 | hashes[h / 32] |= (1 << (h % 32)); |
1025 | #else | | 1030 | #else |
1026 | hashes[0] = 0xffffffffUL; | | 1031 | hashes[0] = 0xffffffffUL; |
1027 | hashes[1] = 0xffffffffUL; | | 1032 | hashes[1] = 0xffffffffUL; |
1028 | #endif | | 1033 | #endif |
1029 | cfg |= ETH_CFG_MTI; | | 1034 | cfg |= ETH_CFG_MTI; |
1030 | } | | 1035 | } |
1031 | ETHER_NEXT_MULTI(step, enm); | | 1036 | ETHER_NEXT_MULTI(step, enm); |
1032 | nma++; | | 1037 | nma++; |
1033 | } | | 1038 | } |
1034 | ETHER_UNLOCK(ec); | | 1039 | ETHER_UNLOCK(ec); |
1035 | | | 1040 | |
1036 | // program... | | 1041 | // program... |
1037 | DPRINTFN(1,("%s: en0 %02x:%02x:%02x:%02x:%02x:%02x\n", __FUNCTION__, | | 1042 | DPRINTFN(1,("%s: en0 %02x:%02x:%02x:%02x:%02x:%02x\n", __FUNCTION__, |
1038 | sc->sc_enaddr[0], sc->sc_enaddr[1], sc->sc_enaddr[2], | | 1043 | sc->sc_enaddr[0], sc->sc_enaddr[1], sc->sc_enaddr[2], |
1039 | sc->sc_enaddr[3], sc->sc_enaddr[4], sc->sc_enaddr[5])); | | 1044 | sc->sc_enaddr[3], sc->sc_enaddr[4], sc->sc_enaddr[5])); |
1040 | CEMAC_GEM_WRITE(SA1L, (sc->sc_enaddr[3] << 24) | | 1045 | CEMAC_GEM_WRITE(SA1L, (sc->sc_enaddr[3] << 24) |
1041 | | (sc->sc_enaddr[2] << 16) | (sc->sc_enaddr[1] << 8) | | 1046 | | (sc->sc_enaddr[2] << 16) | (sc->sc_enaddr[1] << 8) |
1042 | | (sc->sc_enaddr[0])); | | 1047 | | (sc->sc_enaddr[0])); |
1043 | CEMAC_GEM_WRITE(SA1H, (sc->sc_enaddr[5] << 8) | | 1048 | CEMAC_GEM_WRITE(SA1H, (sc->sc_enaddr[5] << 8) |
1044 | | (sc->sc_enaddr[4])); | | 1049 | | (sc->sc_enaddr[4])); |
1045 | if (nma > 0) { | | 1050 | if (nma > 0) { |
1046 | DPRINTFN(1,("%s: en1 %02x:%02x:%02x:%02x:%02x:%02x\n", __FUNCTION__, | | 1051 | DPRINTFN(1,("%s: en1 %02x:%02x:%02x:%02x:%02x:%02x\n", __FUNCTION__, |
1047 | ias[0][0], ias[0][1], ias[0][2], | | 1052 | ias[0][0], ias[0][1], ias[0][2], |
1048 | ias[0][3], ias[0][4], ias[0][5])); | | 1053 | ias[0][3], ias[0][4], ias[0][5])); |
1049 | CEMAC_WRITE(ETH_SA2L, (ias[0][3] << 24) | | 1054 | CEMAC_WRITE(ETH_SA2L, (ias[0][3] << 24) |
1050 | | (ias[0][2] << 16) | (ias[0][1] << 8) | | 1055 | | (ias[0][2] << 16) | (ias[0][1] << 8) |
1051 | | (ias[0][0])); | | 1056 | | (ias[0][0])); |
1052 | CEMAC_WRITE(ETH_SA2H, (ias[0][4] << 8) | | 1057 | CEMAC_WRITE(ETH_SA2H, (ias[0][4] << 8) |
1053 | | (ias[0][5])); | | 1058 | | (ias[0][5])); |
1054 | } | | 1059 | } |
1055 | if (nma > 1) { | | 1060 | if (nma > 1) { |
1056 | DPRINTFN(1,("%s: en2 %02x:%02x:%02x:%02x:%02x:%02x\n", __FUNCTION__, | | 1061 | DPRINTFN(1,("%s: en2 %02x:%02x:%02x:%02x:%02x:%02x\n", __FUNCTION__, |
1057 | ias[1][0], ias[1][1], ias[1][2], | | 1062 | ias[1][0], ias[1][1], ias[1][2], |
1058 | ias[1][3], ias[1][4], ias[1][5])); | | 1063 | ias[1][3], ias[1][4], ias[1][5])); |
1059 | CEMAC_WRITE(ETH_SA3L, (ias[1][3] << 24) | | 1064 | CEMAC_WRITE(ETH_SA3L, (ias[1][3] << 24) |
1060 | | (ias[1][2] << 16) | (ias[1][1] << 8) | | 1065 | | (ias[1][2] << 16) | (ias[1][1] << 8) |
1061 | | (ias[1][0])); | | 1066 | | (ias[1][0])); |
1062 | CEMAC_WRITE(ETH_SA3H, (ias[1][4] << 8) | | 1067 | CEMAC_WRITE(ETH_SA3H, (ias[1][4] << 8) |
1063 | | (ias[1][5])); | | 1068 | | (ias[1][5])); |
1064 | } | | 1069 | } |
1065 | if (nma > 2) { | | 1070 | if (nma > 2) { |
1066 | DPRINTFN(1,("%s: en3 %02x:%02x:%02x:%02x:%02x:%02x\n", __FUNCTION__, | | 1071 | DPRINTFN(1,("%s: en3 %02x:%02x:%02x:%02x:%02x:%02x\n", __FUNCTION__, |
1067 | ias[2][0], ias[2][1], ias[2][2], | | 1072 | ias[2][0], ias[2][1], ias[2][2], |
1068 | ias[2][3], ias[2][4], ias[2][5])); | | 1073 | ias[2][3], ias[2][4], ias[2][5])); |
1069 | CEMAC_WRITE(ETH_SA4L, (ias[2][3] << 24) | | 1074 | CEMAC_WRITE(ETH_SA4L, (ias[2][3] << 24) |
1070 | | (ias[2][2] << 16) | (ias[2][1] << 8) | | 1075 | | (ias[2][2] << 16) | (ias[2][1] << 8) |
1071 | | (ias[2][0])); | | 1076 | | (ias[2][0])); |
1072 | CEMAC_WRITE(ETH_SA4H, (ias[2][4] << 8) | | 1077 | CEMAC_WRITE(ETH_SA4H, (ias[2][4] << 8) |
1073 | | (ias[2][5])); | | 1078 | | (ias[2][5])); |
1074 | } | | 1079 | } |
1075 | CEMAC_GEM_WRITE(HSH, hashes[0]); | | 1080 | CEMAC_GEM_WRITE(HSH, hashes[0]); |
1076 | CEMAC_GEM_WRITE(HSL, hashes[1]); | | 1081 | CEMAC_GEM_WRITE(HSL, hashes[1]); |
1077 | CEMAC_WRITE(ETH_CFG, cfg); | | 1082 | CEMAC_WRITE(ETH_CFG, cfg); |
1078 | CEMAC_WRITE(ETH_CTL, ctl | ETH_CTL_RE); | | 1083 | CEMAC_WRITE(ETH_CTL, ctl | ETH_CTL_RE); |
1079 | } | | 1084 | } |