| @@ -1,784 +1,782 @@ | | | @@ -1,784 +1,782 @@ |
1 | /* $NetBSD: if_ec.c,v 1.33 2008/04/28 20:23:52 martin Exp $ */ | | 1 | /* $NetBSD: if_ec.c,v 1.34 2011/04/24 18:54:41 plunky Exp $ */ |
2 | | | 2 | |
3 | /*- | | 3 | /*- |
4 | * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc. | | 4 | * Copyright (c) 1997, 1998 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 of the Numerical Aerospace Simulation Facility, | | 8 | * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, |
9 | * NASA Ames Research Center. | | 9 | * NASA Ames Research Center. |
10 | * | | 10 | * |
11 | * Redistribution and use in source and binary forms, with or without | | 11 | * Redistribution and use in source and binary forms, with or without |
12 | * modification, are permitted provided that the following conditions | | 12 | * modification, are permitted provided that the following conditions |
13 | * are met: | | 13 | * are met: |
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 the | | 17 | * notice, this list of conditions and the following disclaimer in the |
18 | * documentation and/or other materials provided with the distribution. | | 18 | * documentation and/or other materials provided with the distribution. |
19 | * | | 19 | * |
20 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | | 20 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
21 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | | 21 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
22 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | | 22 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
23 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | | 23 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
24 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | | 24 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
25 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | 25 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
26 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | 26 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
27 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | 27 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
28 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | 28 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
29 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | | 29 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
30 | * POSSIBILITY OF SUCH DAMAGE. | | 30 | * POSSIBILITY OF SUCH DAMAGE. |
31 | */ | | 31 | */ |
32 | | | 32 | |
33 | /* | | 33 | /* |
34 | * Device driver for National Semiconductor DS8390/WD83C690 based ethernet | | 34 | * Device driver for National Semiconductor DS8390/WD83C690 based ethernet |
35 | * adapters. | | 35 | * adapters. |
36 | * | | 36 | * |
37 | * Copyright (c) 1994, 1995 Charles M. Hannum. All rights reserved. | | 37 | * Copyright (c) 1994, 1995 Charles M. Hannum. All rights reserved. |
38 | * | | 38 | * |
39 | * Copyright (C) 1993, David Greenman. This software may be used, modified, | | 39 | * Copyright (C) 1993, David Greenman. This software may be used, modified, |
40 | * copied, distributed, and sold, in both source and binary form provided that | | 40 | * copied, distributed, and sold, in both source and binary form provided that |
41 | * the above copyright and these terms are retained. Under no circumstances is | | 41 | * the above copyright and these terms are retained. Under no circumstances is |
42 | * the author responsible for the proper functioning of this software, nor does | | 42 | * the author responsible for the proper functioning of this software, nor does |
43 | * the author assume any responsibility for damages incurred with its use. | | 43 | * the author assume any responsibility for damages incurred with its use. |
44 | */ | | 44 | */ |
45 | | | 45 | |
46 | /* | | 46 | /* |
47 | * Device driver for the 3Com Etherlink II (3c503). | | 47 | * Device driver for the 3Com Etherlink II (3c503). |
48 | */ | | 48 | */ |
49 | | | 49 | |
50 | #include <sys/cdefs.h> | | 50 | #include <sys/cdefs.h> |
51 | __KERNEL_RCSID(0, "$NetBSD: if_ec.c,v 1.33 2008/04/28 20:23:52 martin Exp $"); | | 51 | __KERNEL_RCSID(0, "$NetBSD: if_ec.c,v 1.34 2011/04/24 18:54:41 plunky Exp $"); |
52 | | | 52 | |
53 | #include <sys/param.h> | | 53 | #include <sys/param.h> |
54 | #include <sys/systm.h> | | 54 | #include <sys/systm.h> |
55 | #include <sys/device.h> | | 55 | #include <sys/device.h> |
56 | #include <sys/socket.h> | | 56 | #include <sys/socket.h> |
57 | #include <sys/mbuf.h> | | 57 | #include <sys/mbuf.h> |
58 | #include <sys/syslog.h> | | 58 | #include <sys/syslog.h> |
59 | | | 59 | |
60 | #include <net/if.h> | | 60 | #include <net/if.h> |
61 | #include <net/if_dl.h> | | 61 | #include <net/if_dl.h> |
62 | #include <net/if_types.h> | | 62 | #include <net/if_types.h> |
63 | #include <net/if_media.h> | | 63 | #include <net/if_media.h> |
64 | | | 64 | |
65 | #include <net/if_ether.h> | | 65 | #include <net/if_ether.h> |
66 | | | 66 | |
67 | #include <sys/bus.h> | | 67 | #include <sys/bus.h> |
68 | #include <sys/intr.h> | | 68 | #include <sys/intr.h> |
69 | | | 69 | |
70 | #include <dev/isa/isareg.h> | | 70 | #include <dev/isa/isareg.h> |
71 | #include <dev/isa/isavar.h> | | 71 | #include <dev/isa/isavar.h> |
72 | | | 72 | |
73 | #include <dev/ic/dp8390reg.h> | | 73 | #include <dev/ic/dp8390reg.h> |
74 | #include <dev/ic/dp8390var.h> | | 74 | #include <dev/ic/dp8390var.h> |
75 | | | 75 | |
76 | #include <dev/isa/if_ecreg.h> | | 76 | #include <dev/isa/if_ecreg.h> |
77 | | | 77 | |
78 | struct ec_softc { | | 78 | struct ec_softc { |
79 | struct dp8390_softc sc_dp8390; | | 79 | struct dp8390_softc sc_dp8390; |
80 | | | 80 | |
81 | bus_space_tag_t sc_asict; /* space tag for ASIC */ | | 81 | bus_space_tag_t sc_asict; /* space tag for ASIC */ |
82 | bus_space_handle_t sc_asich; /* space handle for ASIC */ | | 82 | bus_space_handle_t sc_asich; /* space handle for ASIC */ |
83 | | | 83 | |
84 | int sc_16bitp; /* are we 16 bit? */ | | 84 | int sc_16bitp; /* are we 16 bit? */ |
85 | | | 85 | |
86 | void *sc_ih; /* interrupt handle */ | | 86 | void *sc_ih; /* interrupt handle */ |
87 | }; | | 87 | }; |
88 | | | 88 | |
89 | int ec_probe(device_t, cfdata_t, void *); | | 89 | int ec_probe(device_t, cfdata_t, void *); |
90 | void ec_attach(device_t, device_t, void *); | | 90 | void ec_attach(device_t, device_t, void *); |
91 | | | 91 | |
92 | CFATTACH_DECL_NEW(ec, sizeof(struct ec_softc), | | 92 | CFATTACH_DECL_NEW(ec, sizeof(struct ec_softc), |
93 | ec_probe, ec_attach, NULL, NULL); | | 93 | ec_probe, ec_attach, NULL, NULL); |
94 | | | 94 | |
95 | int ec_set_media(struct ec_softc *, int); | | 95 | int ec_set_media(struct ec_softc *, int); |
96 | | | 96 | |
97 | void ec_media_init(struct dp8390_softc *); | | 97 | void ec_media_init(struct dp8390_softc *); |
98 | | | 98 | |
99 | int ec_mediachange(struct dp8390_softc *); | | 99 | int ec_mediachange(struct dp8390_softc *); |
100 | void ec_mediastatus(struct dp8390_softc *, struct ifmediareq *); | | 100 | void ec_mediastatus(struct dp8390_softc *, struct ifmediareq *); |
101 | | | 101 | |
102 | void ec_init_card(struct dp8390_softc *); | | 102 | void ec_init_card(struct dp8390_softc *); |
103 | int ec_write_mbuf(struct dp8390_softc *, struct mbuf *, int); | | 103 | int ec_write_mbuf(struct dp8390_softc *, struct mbuf *, int); |
104 | int ec_ring_copy(struct dp8390_softc *, int, void *, u_short); | | 104 | int ec_ring_copy(struct dp8390_softc *, int, void *, u_short); |
105 | void ec_read_hdr(struct dp8390_softc *, int, struct dp8390_ring *); | | 105 | void ec_read_hdr(struct dp8390_softc *, int, struct dp8390_ring *); |
106 | int ec_fake_test_mem(struct dp8390_softc *); | | 106 | int ec_fake_test_mem(struct dp8390_softc *); |
107 | int ec_test_mem(struct dp8390_softc *); | | 107 | int ec_test_mem(struct dp8390_softc *); |
108 | | | 108 | |
109 | inline void ec_readmem(struct ec_softc *, int, u_int8_t *, int); | | | |
110 | | | | |
111 | static const int ec_iobase[] = { | | 109 | static const int ec_iobase[] = { |
112 | 0x2e0, 0x2a0, 0x280, 0x250, 0x350, 0x330, 0x310, 0x300, | | 110 | 0x2e0, 0x2a0, 0x280, 0x250, 0x350, 0x330, 0x310, 0x300, |
113 | }; | | 111 | }; |
114 | #define NEC_IOBASE (sizeof(ec_iobase) / sizeof(ec_iobase[0])) | | 112 | #define NEC_IOBASE (sizeof(ec_iobase) / sizeof(ec_iobase[0])) |
115 | | | 113 | |
116 | static const int ec_membase[] = { | | 114 | static const int ec_membase[] = { |
117 | -1, -1, -1, -1, | | 115 | -1, -1, -1, -1, |
118 | 0xc8000, 0xcc000, 0xd8000, 0xdc000, | | 116 | 0xc8000, 0xcc000, 0xd8000, 0xdc000, |
119 | }; | | 117 | }; |
120 | #define NEC_MEMBASE (sizeof(ec_membase) / sizeof(ec_membase[0])) | | 118 | #define NEC_MEMBASE (sizeof(ec_membase) / sizeof(ec_membase[0])) |
121 | | | 119 | |
122 | int | | 120 | int |
123 | ec_probe(device_t parent, cfdata_t match, void *aux) | | 121 | ec_probe(device_t parent, cfdata_t match, void *aux) |
124 | { | | 122 | { |
125 | struct isa_attach_args *ia = aux; | | 123 | struct isa_attach_args *ia = aux; |
126 | bus_space_tag_t nict, asict, memt; | | 124 | bus_space_tag_t nict, asict, memt; |
127 | bus_space_handle_t nich, asich, memh; | | 125 | bus_space_handle_t nich, asich, memh; |
128 | bus_size_t memsize; | | 126 | bus_size_t memsize; |
129 | int nich_valid, asich_valid, memh_valid; | | 127 | int nich_valid, asich_valid, memh_valid; |
130 | int i, rv = 0; | | 128 | int i, rv = 0; |
131 | u_int8_t x; | | 129 | u_int8_t x; |
132 | | | 130 | |
133 | nict = asict = ia->ia_iot; | | 131 | nict = asict = ia->ia_iot; |
134 | memt = ia->ia_memt; | | 132 | memt = ia->ia_memt; |
135 | | | 133 | |
136 | nich_valid = asich_valid = memh_valid = 0; | | 134 | nich_valid = asich_valid = memh_valid = 0; |
137 | | | 135 | |
138 | /* | | 136 | /* |
139 | * Hmm, a 16-bit card has 16k of memory, but only an 8k window | | 137 | * Hmm, a 16-bit card has 16k of memory, but only an 8k window |
140 | * to it. | | 138 | * to it. |
141 | */ | | 139 | */ |
142 | memsize = 8192; | | 140 | memsize = 8192; |
143 | | | 141 | |
144 | if (ia->ia_nio < 1) | | 142 | if (ia->ia_nio < 1) |
145 | return (0); | | 143 | return (0); |
146 | if (ia->ia_niomem < 1) | | 144 | if (ia->ia_niomem < 1) |
147 | return (0); | | 145 | return (0); |
148 | if (ia->ia_nirq < 1) | | 146 | if (ia->ia_nirq < 1) |
149 | return (0); | | 147 | return (0); |
150 | | | 148 | |
151 | if (ISA_DIRECT_CONFIG(ia)) | | 149 | if (ISA_DIRECT_CONFIG(ia)) |
152 | return (0); | | 150 | return (0); |
153 | | | 151 | |
154 | /* Disallow wildcarded i/o addresses. */ | | 152 | /* Disallow wildcarded i/o addresses. */ |
155 | if (ia->ia_io[0].ir_addr == ISA_UNKNOWN_PORT) | | 153 | if (ia->ia_io[0].ir_addr == ISA_UNKNOWN_PORT) |
156 | return (0); | | 154 | return (0); |
157 | | | 155 | |
158 | /* Disallow wildcarded mem address. */ | | 156 | /* Disallow wildcarded mem address. */ |
159 | if (ia->ia_iomem[0].ir_addr == ISA_UNKNOWN_IOMEM) | | 157 | if (ia->ia_iomem[0].ir_addr == ISA_UNKNOWN_IOMEM) |
160 | return (0); | | 158 | return (0); |
161 | | | 159 | |
162 | /* Validate the i/o base. */ | | 160 | /* Validate the i/o base. */ |
163 | for (i = 0; i < NEC_IOBASE; i++) | | 161 | for (i = 0; i < NEC_IOBASE; i++) |
164 | if (ia->ia_io[0].ir_addr == ec_iobase[i]) | | 162 | if (ia->ia_io[0].ir_addr == ec_iobase[i]) |
165 | break; | | 163 | break; |
166 | if (i == NEC_IOBASE) | | 164 | if (i == NEC_IOBASE) |
167 | return (0); | | 165 | return (0); |
168 | | | 166 | |
169 | /* Validate the mem base. */ | | 167 | /* Validate the mem base. */ |
170 | for (i = 0; i < NEC_MEMBASE; i++) { | | 168 | for (i = 0; i < NEC_MEMBASE; i++) { |
171 | if (ec_membase[i] == -1) | | 169 | if (ec_membase[i] == -1) |
172 | continue; | | 170 | continue; |
173 | if (ia->ia_iomem[0].ir_addr == ec_membase[i]) | | 171 | if (ia->ia_iomem[0].ir_addr == ec_membase[i]) |
174 | break; | | 172 | break; |
175 | } | | 173 | } |
176 | if (i == NEC_MEMBASE) | | 174 | if (i == NEC_MEMBASE) |
177 | return (0); | | 175 | return (0); |
178 | | | 176 | |
179 | /* Attempt to map the NIC space. */ | | 177 | /* Attempt to map the NIC space. */ |
180 | if (bus_space_map(nict, ia->ia_io[0].ir_addr + ELINK2_NIC_OFFSET, | | 178 | if (bus_space_map(nict, ia->ia_io[0].ir_addr + ELINK2_NIC_OFFSET, |
181 | ELINK2_NIC_PORTS, 0, &nich)) | | 179 | ELINK2_NIC_PORTS, 0, &nich)) |
182 | goto out; | | 180 | goto out; |
183 | nich_valid = 1; | | 181 | nich_valid = 1; |
184 | | | 182 | |
185 | /* Attempt to map the ASIC space. */ | | 183 | /* Attempt to map the ASIC space. */ |
186 | if (bus_space_map(asict, ia->ia_io[0].ir_addr + ELINK2_ASIC_OFFSET, | | 184 | if (bus_space_map(asict, ia->ia_io[0].ir_addr + ELINK2_ASIC_OFFSET, |
187 | ELINK2_ASIC_PORTS, 0, &asich)) | | 185 | ELINK2_ASIC_PORTS, 0, &asich)) |
188 | goto out; | | 186 | goto out; |
189 | asich_valid = 1; | | 187 | asich_valid = 1; |
190 | | | 188 | |
191 | /* Attempt to map the memory space. */ | | 189 | /* Attempt to map the memory space. */ |
192 | if (bus_space_map(memt, ia->ia_iomem[0].ir_addr, memsize, 0, &memh)) | | 190 | if (bus_space_map(memt, ia->ia_iomem[0].ir_addr, memsize, 0, &memh)) |
193 | goto out; | | 191 | goto out; |
194 | memh_valid = 1; | | 192 | memh_valid = 1; |
195 | | | 193 | |
196 | /* | | 194 | /* |
197 | * Verify that the kernel configured I/O address matches the | | 195 | * Verify that the kernel configured I/O address matches the |
198 | * board configured I/O address. | | 196 | * board configured I/O address. |
199 | * | | 197 | * |
200 | * This is really only useful to see if something that looks like | | 198 | * This is really only useful to see if something that looks like |
201 | * the board is there; after all, we're already talking to it at | | 199 | * the board is there; after all, we're already talking to it at |
202 | * this point. | | 200 | * this point. |
203 | */ | | 201 | */ |
204 | x = bus_space_read_1(asict, asich, ELINK2_BCFR); | | 202 | x = bus_space_read_1(asict, asich, ELINK2_BCFR); |
205 | if (x == 0 || (x & (x - 1)) != 0) | | 203 | if (x == 0 || (x & (x - 1)) != 0) |
206 | goto out; | | 204 | goto out; |
207 | i = ffs(x) - 1; | | 205 | i = ffs(x) - 1; |
208 | if (ia->ia_io[0].ir_addr != ec_iobase[i]) | | 206 | if (ia->ia_io[0].ir_addr != ec_iobase[i]) |
209 | goto out; | | 207 | goto out; |
210 | | | 208 | |
211 | /* | | 209 | /* |
212 | * ...and for the memory address. Note we do not support | | 210 | * ...and for the memory address. Note we do not support |
213 | * cards configured with shared memory disabled. | | 211 | * cards configured with shared memory disabled. |
214 | */ | | 212 | */ |
215 | x = bus_space_read_1(asict, asich, ELINK2_PCFR); | | 213 | x = bus_space_read_1(asict, asich, ELINK2_PCFR); |
216 | if (x == 0 || (x & (x - 1)) != 0) | | 214 | if (x == 0 || (x & (x - 1)) != 0) |
217 | goto out; | | 215 | goto out; |
218 | i = ffs(x) - 1; | | 216 | i = ffs(x) - 1; |
219 | if (ia->ia_iomem[0].ir_addr != ec_membase[i]) | | 217 | if (ia->ia_iomem[0].ir_addr != ec_membase[i]) |
220 | goto out; | | 218 | goto out; |
221 | | | 219 | |
222 | /* So, we say we've found it! */ | | 220 | /* So, we say we've found it! */ |
223 | ia->ia_nio = 1; /* XXX Really 2! */ | | 221 | ia->ia_nio = 1; /* XXX Really 2! */ |
224 | ia->ia_io[0].ir_size = ELINK2_NIC_PORTS; | | 222 | ia->ia_io[0].ir_size = ELINK2_NIC_PORTS; |
225 | | | 223 | |
226 | ia->ia_niomem = 1; | | 224 | ia->ia_niomem = 1; |
227 | ia->ia_iomem[0].ir_size = memsize; | | 225 | ia->ia_iomem[0].ir_size = memsize; |
228 | | | 226 | |
229 | ia->ia_nirq = 1; | | 227 | ia->ia_nirq = 1; |
230 | | | 228 | |
231 | ia->ia_ndrq = 0; | | 229 | ia->ia_ndrq = 0; |
232 | | | 230 | |
233 | rv = 1; | | 231 | rv = 1; |
234 | | | 232 | |
235 | out: | | 233 | out: |
236 | if (nich_valid) | | 234 | if (nich_valid) |
237 | bus_space_unmap(nict, nich, ELINK2_NIC_PORTS); | | 235 | bus_space_unmap(nict, nich, ELINK2_NIC_PORTS); |
238 | if (asich_valid) | | 236 | if (asich_valid) |
239 | bus_space_unmap(asict, asich, ELINK2_ASIC_PORTS); | | 237 | bus_space_unmap(asict, asich, ELINK2_ASIC_PORTS); |
240 | if (memh_valid) | | 238 | if (memh_valid) |
241 | bus_space_unmap(memt, memh, memsize); | | 239 | bus_space_unmap(memt, memh, memsize); |
242 | return (rv); | | 240 | return (rv); |
243 | } | | 241 | } |
244 | | | 242 | |
245 | void | | 243 | void |
246 | ec_attach(device_t parent, device_t self, void *aux) | | 244 | ec_attach(device_t parent, device_t self, void *aux) |
247 | { | | 245 | { |
248 | struct ec_softc *esc = device_private(self); | | 246 | struct ec_softc *esc = device_private(self); |
249 | struct dp8390_softc *sc = &esc->sc_dp8390; | | 247 | struct dp8390_softc *sc = &esc->sc_dp8390; |
250 | struct isa_attach_args *ia = aux; | | 248 | struct isa_attach_args *ia = aux; |
251 | bus_space_tag_t nict, asict, memt; | | 249 | bus_space_tag_t nict, asict, memt; |
252 | bus_space_handle_t nich, asich, memh; | | 250 | bus_space_handle_t nich, asich, memh; |
253 | bus_size_t memsize; | | 251 | bus_size_t memsize; |
254 | u_int8_t tmp; | | 252 | u_int8_t tmp; |
255 | int i; | | 253 | int i; |
256 | | | 254 | |
257 | sc->sc_dev = self; | | 255 | sc->sc_dev = self; |
258 | aprint_normal("\n"); | | 256 | aprint_normal("\n"); |
259 | | | 257 | |
260 | nict = asict = ia->ia_iot; | | 258 | nict = asict = ia->ia_iot; |
261 | memt = ia->ia_memt; | | 259 | memt = ia->ia_memt; |
262 | | | 260 | |
263 | /* | | 261 | /* |
264 | * Hmm, a 16-bit card has 16k of memory, but only an 8k window | | 262 | * Hmm, a 16-bit card has 16k of memory, but only an 8k window |
265 | * to it. | | 263 | * to it. |
266 | */ | | 264 | */ |
267 | memsize = ia->ia_iomem[0].ir_size; | | 265 | memsize = ia->ia_iomem[0].ir_size; |
268 | | | 266 | |
269 | /* Map the NIC space. */ | | 267 | /* Map the NIC space. */ |
270 | if (bus_space_map(nict, ia->ia_io[0].ir_addr + ELINK2_NIC_OFFSET, | | 268 | if (bus_space_map(nict, ia->ia_io[0].ir_addr + ELINK2_NIC_OFFSET, |
271 | ELINK2_NIC_PORTS, 0, &nich)) { | | 269 | ELINK2_NIC_PORTS, 0, &nich)) { |
272 | aprint_error_dev(self, "can't map nic i/o space\n"); | | 270 | aprint_error_dev(self, "can't map nic i/o space\n"); |
273 | return; | | 271 | return; |
274 | } | | 272 | } |
275 | | | 273 | |
276 | /* Map the ASIC space. */ | | 274 | /* Map the ASIC space. */ |
277 | if (bus_space_map(asict, ia->ia_io[0].ir_addr + ELINK2_ASIC_OFFSET, | | 275 | if (bus_space_map(asict, ia->ia_io[0].ir_addr + ELINK2_ASIC_OFFSET, |
278 | ELINK2_ASIC_PORTS, 0, &asich)) { | | 276 | ELINK2_ASIC_PORTS, 0, &asich)) { |
279 | aprint_error_dev(self, "can't map asic i/o space\n"); | | 277 | aprint_error_dev(self, "can't map asic i/o space\n"); |
280 | return; | | 278 | return; |
281 | } | | 279 | } |
282 | | | 280 | |
283 | /* Map the memory space. */ | | 281 | /* Map the memory space. */ |
284 | if (bus_space_map(memt, ia->ia_iomem[0].ir_addr, memsize, 0, &memh)) { | | 282 | if (bus_space_map(memt, ia->ia_iomem[0].ir_addr, memsize, 0, &memh)) { |
285 | aprint_error_dev(self, "can't map shared memory\n"); | | 283 | aprint_error_dev(self, "can't map shared memory\n"); |
286 | return; | | 284 | return; |
287 | } | | 285 | } |
288 | | | 286 | |
289 | esc->sc_asict = asict; | | 287 | esc->sc_asict = asict; |
290 | esc->sc_asich = asich; | | 288 | esc->sc_asich = asich; |
291 | | | 289 | |
292 | sc->sc_regt = nict; | | 290 | sc->sc_regt = nict; |
293 | sc->sc_regh = nich; | | 291 | sc->sc_regh = nich; |
294 | | | 292 | |
295 | sc->sc_buft = memt; | | 293 | sc->sc_buft = memt; |
296 | sc->sc_bufh = memh; | | 294 | sc->sc_bufh = memh; |
297 | | | 295 | |
298 | /* Interface is always enabled. */ | | 296 | /* Interface is always enabled. */ |
299 | sc->sc_enabled = 1; | | 297 | sc->sc_enabled = 1; |
300 | | | 298 | |
301 | /* Registers are linear. */ | | 299 | /* Registers are linear. */ |
302 | for (i = 0; i < 16; i++) | | 300 | for (i = 0; i < 16; i++) |
303 | sc->sc_reg_map[i] = i; | | 301 | sc->sc_reg_map[i] = i; |
304 | | | 302 | |
305 | /* Now we can use the NIC_{GET,PUT}() macros. */ | | 303 | /* Now we can use the NIC_{GET,PUT}() macros. */ |
306 | | | 304 | |
307 | /* | | 305 | /* |
308 | * Reset NIC and ASIC. Enable on-board transeiver throughout | | 306 | * Reset NIC and ASIC. Enable on-board transeiver throughout |
309 | * reset sequence since it will lock up if the cable isn't | | 307 | * reset sequence since it will lock up if the cable isn't |
310 | * connected if we don't. | | 308 | * connected if we don't. |
311 | */ | | 309 | */ |
312 | bus_space_write_1(asict, asich, ELINK2_CR, | | 310 | bus_space_write_1(asict, asich, ELINK2_CR, |
313 | ELINK2_CR_RST | ELINK2_CR_XSEL); | | 311 | ELINK2_CR_RST | ELINK2_CR_XSEL); |
314 | | | 312 | |
315 | /* Wait for a while, then un-reset it. */ | | 313 | /* Wait for a while, then un-reset it. */ |
316 | delay(50); | | 314 | delay(50); |
317 | | | 315 | |
318 | /* | | 316 | /* |
319 | * The 3Com ASIC defaults to rather strange settings for the CR | | 317 | * The 3Com ASIC defaults to rather strange settings for the CR |
320 | * after a reset. It's important to set it again after the | | 318 | * after a reset. It's important to set it again after the |
321 | * following write (this is done when we map the PROM below). | | 319 | * following write (this is done when we map the PROM below). |
322 | */ | | 320 | */ |
323 | bus_space_write_1(asict, asich, ELINK2_CR, ELINK2_CR_XSEL); | | 321 | bus_space_write_1(asict, asich, ELINK2_CR, ELINK2_CR_XSEL); |
324 | | | 322 | |
325 | /* Wait a bit for the NIC to recover from the reset. */ | | 323 | /* Wait a bit for the NIC to recover from the reset. */ |
326 | delay(5000); | | 324 | delay(5000); |
327 | | | 325 | |
328 | /* | | 326 | /* |
329 | * Get the station address from on-board ROM. | | 327 | * Get the station address from on-board ROM. |
330 | * | | 328 | * |
331 | * First, map Ethernet address PROM over the top of where the NIC | | 329 | * First, map Ethernet address PROM over the top of where the NIC |
332 | * registers normally appear. | | 330 | * registers normally appear. |
333 | */ | | 331 | */ |
334 | bus_space_write_1(asict, asich, ELINK2_CR, | | 332 | bus_space_write_1(asict, asich, ELINK2_CR, |
335 | ELINK2_CR_XSEL | ELINK2_CR_EALO); | | 333 | ELINK2_CR_XSEL | ELINK2_CR_EALO); |
336 | | | 334 | |
337 | for (i = 0; i < ETHER_ADDR_LEN; i++) | | 335 | for (i = 0; i < ETHER_ADDR_LEN; i++) |
338 | sc->sc_enaddr[i] = NIC_GET(nict, nich, i); | | 336 | sc->sc_enaddr[i] = NIC_GET(nict, nich, i); |
339 | | | 337 | |
340 | /* | | 338 | /* |
341 | * Unmap PROM - select NIC registers. The proper setting of the | | 339 | * Unmap PROM - select NIC registers. The proper setting of the |
342 | * transceiver is set in later in ec_init_card() via dp8390_init(). | | 340 | * transceiver is set in later in ec_init_card() via dp8390_init(). |
343 | */ | | 341 | */ |
344 | bus_space_write_1(asict, asich, ELINK2_CR, ELINK2_CR_XSEL); | | 342 | bus_space_write_1(asict, asich, ELINK2_CR, ELINK2_CR_XSEL); |
345 | | | 343 | |
346 | /* Determine if this is an 8-bit or 16-bit board. */ | | 344 | /* Determine if this is an 8-bit or 16-bit board. */ |
347 | | | 345 | |
348 | /* Select page 0 registers. */ | | 346 | /* Select page 0 registers. */ |
349 | NIC_PUT(nict, nich, ED_P0_CR, ED_CR_RD2 | ED_CR_PAGE_0 | ED_CR_STP); | | 347 | NIC_PUT(nict, nich, ED_P0_CR, ED_CR_RD2 | ED_CR_PAGE_0 | ED_CR_STP); |
350 | | | 348 | |
351 | /* | | 349 | /* |
352 | * Attempt to clear WTS. If it doesn't clear, then this is a | | 350 | * Attempt to clear WTS. If it doesn't clear, then this is a |
353 | * 16-bit board. | | 351 | * 16-bit board. |
354 | */ | | 352 | */ |
355 | NIC_PUT(nict, nich, ED_P0_DCR, 0); | | 353 | NIC_PUT(nict, nich, ED_P0_DCR, 0); |
356 | | | 354 | |
357 | /* Select page 2 registers. */ | | 355 | /* Select page 2 registers. */ |
358 | NIC_PUT(nict, nich, ED_P0_CR, ED_CR_RD2 | ED_CR_PAGE_2 | ED_CR_STP); | | 356 | NIC_PUT(nict, nich, ED_P0_CR, ED_CR_RD2 | ED_CR_PAGE_2 | ED_CR_STP); |
359 | | | 357 | |
360 | /* The 3c503 forces the WTS bit to a one if this is a 16-bit board. */ | | 358 | /* The 3c503 forces the WTS bit to a one if this is a 16-bit board. */ |
361 | if (NIC_GET(nict, nich, ED_P2_DCR) & ED_DCR_WTS) | | 359 | if (NIC_GET(nict, nich, ED_P2_DCR) & ED_DCR_WTS) |
362 | esc->sc_16bitp = 1; | | 360 | esc->sc_16bitp = 1; |
363 | else | | 361 | else |
364 | esc->sc_16bitp = 0; | | 362 | esc->sc_16bitp = 0; |
365 | | | 363 | |
366 | aprint_normal_dev(self, "3Com 3c503 Ethernet (%s-bit)\n", | | 364 | aprint_normal_dev(self, "3Com 3c503 Ethernet (%s-bit)\n", |
367 | esc->sc_16bitp ? "16" : "8"); | | 365 | esc->sc_16bitp ? "16" : "8"); |
368 | | | 366 | |
369 | /* Select page 0 registers. */ | | 367 | /* Select page 0 registers. */ |
370 | NIC_PUT(nict, nich, ED_P2_CR, ED_CR_RD2 | ED_CR_PAGE_0 | ED_CR_STP); | | 368 | NIC_PUT(nict, nich, ED_P2_CR, ED_CR_RD2 | ED_CR_PAGE_0 | ED_CR_STP); |
371 | | | 369 | |
372 | sc->cr_proto = ED_CR_RD2; | | 370 | sc->cr_proto = ED_CR_RD2; |
373 | | | 371 | |
374 | /* | | 372 | /* |
375 | * DCR gets: | | 373 | * DCR gets: |
376 | * | | 374 | * |
377 | * FIFO threshold to 8, No auto-init Remote DMA, | | 375 | * FIFO threshold to 8, No auto-init Remote DMA, |
378 | * byte order=80x86. | | 376 | * byte order=80x86. |
379 | * | | 377 | * |
380 | * 16-bit cards also get word-wide DMA transfers. | | 378 | * 16-bit cards also get word-wide DMA transfers. |
381 | */ | | 379 | */ |
382 | sc->dcr_reg = ED_DCR_FT1 | ED_DCR_LS | | | 380 | sc->dcr_reg = ED_DCR_FT1 | ED_DCR_LS | |
383 | (esc->sc_16bitp ? ED_DCR_WTS : 0); | | 381 | (esc->sc_16bitp ? ED_DCR_WTS : 0); |
384 | | | 382 | |
385 | sc->test_mem = ec_fake_test_mem; | | 383 | sc->test_mem = ec_fake_test_mem; |
386 | sc->ring_copy = ec_ring_copy; | | 384 | sc->ring_copy = ec_ring_copy; |
387 | sc->write_mbuf = ec_write_mbuf; | | 385 | sc->write_mbuf = ec_write_mbuf; |
388 | sc->read_hdr = ec_read_hdr; | | 386 | sc->read_hdr = ec_read_hdr; |
389 | sc->init_card = ec_init_card; | | 387 | sc->init_card = ec_init_card; |
390 | | | 388 | |
391 | sc->sc_media_init = ec_media_init; | | 389 | sc->sc_media_init = ec_media_init; |
392 | | | 390 | |
393 | sc->sc_mediachange = ec_mediachange; | | 391 | sc->sc_mediachange = ec_mediachange; |
394 | sc->sc_mediastatus = ec_mediastatus; | | 392 | sc->sc_mediastatus = ec_mediastatus; |
395 | | | 393 | |
396 | sc->mem_start = 0; | | 394 | sc->mem_start = 0; |
397 | sc->mem_size = memsize; | | 395 | sc->mem_size = memsize; |
398 | | | 396 | |
399 | /* Do generic parts of attach. */ | | 397 | /* Do generic parts of attach. */ |
400 | if (dp8390_config(sc)) { | | 398 | if (dp8390_config(sc)) { |
401 | aprint_error_dev(self, " configuration failed\n"); | | 399 | aprint_error_dev(self, " configuration failed\n"); |
402 | return; | | 400 | return; |
403 | } | | 401 | } |
404 | | | 402 | |
405 | /* | | 403 | /* |
406 | * We need to override the way dp8390_config() set up our | | 404 | * We need to override the way dp8390_config() set up our |
407 | * shared memory. | | 405 | * shared memory. |
408 | * | | 406 | * |
409 | * We have an entire 8k window to put the transmit buffers on the | | 407 | * We have an entire 8k window to put the transmit buffers on the |
410 | * 16-bit boards. But since the 16bit 3c503's shared memory is only | | 408 | * 16-bit boards. But since the 16bit 3c503's shared memory is only |
411 | * fast enough to overlap the loading of one full-size packet, trying | | 409 | * fast enough to overlap the loading of one full-size packet, trying |
412 | * to load more than 2 buffers can actually leave the transmitter idle | | 410 | * to load more than 2 buffers can actually leave the transmitter idle |
413 | * during the load. So 2 seems the best value. (Although a mix of | | 411 | * during the load. So 2 seems the best value. (Although a mix of |
414 | * variable-sized packets might change this assumption. Nonetheless, | | 412 | * variable-sized packets might change this assumption. Nonetheless, |
415 | * we optimize for linear transfers of same-size packets.) | | 413 | * we optimize for linear transfers of same-size packets.) |
416 | */ | | 414 | */ |
417 | if (esc->sc_16bitp) { | | 415 | if (esc->sc_16bitp) { |
418 | if (device_cfdata(sc->sc_dev)->cf_flags & | | 416 | if (device_cfdata(sc->sc_dev)->cf_flags & |
419 | DP8390_NO_MULTI_BUFFERING) | | 417 | DP8390_NO_MULTI_BUFFERING) |
420 | sc->txb_cnt = 1; | | 418 | sc->txb_cnt = 1; |
421 | else | | 419 | else |
422 | sc->txb_cnt = 2; | | 420 | sc->txb_cnt = 2; |
423 | | | 421 | |
424 | sc->tx_page_start = ELINK2_TX_PAGE_OFFSET_16BIT; | | 422 | sc->tx_page_start = ELINK2_TX_PAGE_OFFSET_16BIT; |
425 | sc->rec_page_start = ELINK2_RX_PAGE_OFFSET_16BIT; | | 423 | sc->rec_page_start = ELINK2_RX_PAGE_OFFSET_16BIT; |
426 | sc->rec_page_stop = (memsize >> ED_PAGE_SHIFT) + | | 424 | sc->rec_page_stop = (memsize >> ED_PAGE_SHIFT) + |
427 | sc->rec_page_start; | | 425 | sc->rec_page_start; |
428 | sc->mem_ring = sc->mem_start; | | 426 | sc->mem_ring = sc->mem_start; |
429 | } else { | | 427 | } else { |
430 | sc->txb_cnt = 1; | | 428 | sc->txb_cnt = 1; |
431 | sc->tx_page_start = ELINK2_TX_PAGE_OFFSET_8BIT; | | 429 | sc->tx_page_start = ELINK2_TX_PAGE_OFFSET_8BIT; |
432 | sc->rec_page_start = sc->tx_page_start + ED_TXBUF_SIZE; | | 430 | sc->rec_page_start = sc->tx_page_start + ED_TXBUF_SIZE; |
433 | sc->rec_page_stop = (memsize >> ED_PAGE_SHIFT) + | | 431 | sc->rec_page_stop = (memsize >> ED_PAGE_SHIFT) + |
434 | sc->tx_page_start; | | 432 | sc->tx_page_start; |
435 | sc->mem_ring = sc->mem_start + | | 433 | sc->mem_ring = sc->mem_start + |
436 | (ED_TXBUF_SIZE << ED_PAGE_SHIFT); | | 434 | (ED_TXBUF_SIZE << ED_PAGE_SHIFT); |
437 | } | | 435 | } |
438 | | | 436 | |
439 | /* | | 437 | /* |
440 | * Initialize CA page start/stop registers. Probably only needed | | 438 | * Initialize CA page start/stop registers. Probably only needed |
441 | * if doing DMA, but what the Hell. | | 439 | * if doing DMA, but what the Hell. |
442 | */ | | 440 | */ |
443 | bus_space_write_1(asict, asich, ELINK2_PSTR, sc->rec_page_start); | | 441 | bus_space_write_1(asict, asich, ELINK2_PSTR, sc->rec_page_start); |
444 | bus_space_write_1(asict, asich, ELINK2_PSPR, sc->rec_page_stop); | | 442 | bus_space_write_1(asict, asich, ELINK2_PSPR, sc->rec_page_stop); |
445 | | | 443 | |
446 | /* | | 444 | /* |
447 | * Program the IRQ. | | 445 | * Program the IRQ. |
448 | */ | | 446 | */ |
449 | switch (ia->ia_irq[0].ir_irq) { | | 447 | switch (ia->ia_irq[0].ir_irq) { |
450 | case 9: tmp = ELINK2_IDCFR_IRQ2; break; | | 448 | case 9: tmp = ELINK2_IDCFR_IRQ2; break; |
451 | case 3: tmp = ELINK2_IDCFR_IRQ3; break; | | 449 | case 3: tmp = ELINK2_IDCFR_IRQ3; break; |
452 | case 4: tmp = ELINK2_IDCFR_IRQ4; break; | | 450 | case 4: tmp = ELINK2_IDCFR_IRQ4; break; |
453 | case 5: tmp = ELINK2_IDCFR_IRQ5; break; | | 451 | case 5: tmp = ELINK2_IDCFR_IRQ5; break; |
454 | break; | | 452 | break; |
455 | | | 453 | |
456 | case ISA_UNKNOWN_IRQ: | | 454 | case ISA_UNKNOWN_IRQ: |
457 | aprint_error_dev(self, "wildcarded IRQ is not allowed\n"); | | 455 | aprint_error_dev(self, "wildcarded IRQ is not allowed\n"); |
458 | return; | | 456 | return; |
459 | | | 457 | |
460 | default: | | 458 | default: |
461 | aprint_error_dev(self, "invalid IRQ %d, must be 3, 4, 5, " | | 459 | aprint_error_dev(self, "invalid IRQ %d, must be 3, 4, 5, " |
462 | "or 9\n", ia->ia_irq[0].ir_irq); | | 460 | "or 9\n", ia->ia_irq[0].ir_irq); |
463 | return; | | 461 | return; |
464 | } | | 462 | } |
465 | | | 463 | |
466 | bus_space_write_1(asict, asich, ELINK2_IDCFR, tmp); | | 464 | bus_space_write_1(asict, asich, ELINK2_IDCFR, tmp); |
467 | | | 465 | |
468 | /* | | 466 | /* |
469 | * Initialize the GA configuration register. Set bank and enable | | 467 | * Initialize the GA configuration register. Set bank and enable |
470 | * shared memory. | | 468 | * shared memory. |
471 | */ | | 469 | */ |
472 | bus_space_write_1(asict, asich, ELINK2_GACFR, | | 470 | bus_space_write_1(asict, asich, ELINK2_GACFR, |
473 | ELINK2_GACFR_RSEL | ELINK2_GACFR_MBS0); | | 471 | ELINK2_GACFR_RSEL | ELINK2_GACFR_MBS0); |
474 | | | 472 | |
475 | /* | | 473 | /* |
476 | * Intialize "Vector Pointer" registers. These gawd-awful things | | 474 | * Intialize "Vector Pointer" registers. These gawd-awful things |
477 | * are compared to 20 bits of the address on the ISA, and if they | | 475 | * are compared to 20 bits of the address on the ISA, and if they |
478 | * match, the shared memory is disabled. We set them to 0xffff0... | | 476 | * match, the shared memory is disabled. We set them to 0xffff0... |
479 | * allegedly the reset vector. | | 477 | * allegedly the reset vector. |
480 | */ | | 478 | */ |
481 | bus_space_write_1(asict, asich, ELINK2_VPTR2, 0xff); | | 479 | bus_space_write_1(asict, asich, ELINK2_VPTR2, 0xff); |
482 | bus_space_write_1(asict, asich, ELINK2_VPTR1, 0xff); | | 480 | bus_space_write_1(asict, asich, ELINK2_VPTR1, 0xff); |
483 | bus_space_write_1(asict, asich, ELINK2_VPTR0, 0x00); | | 481 | bus_space_write_1(asict, asich, ELINK2_VPTR0, 0x00); |
484 | | | 482 | |
485 | /* | | 483 | /* |
486 | * Now run the real memory test. | | 484 | * Now run the real memory test. |
487 | */ | | 485 | */ |
488 | if (ec_test_mem(sc)) { | | 486 | if (ec_test_mem(sc)) { |
489 | aprint_error_dev(self, "memory test failed\n"); | | 487 | aprint_error_dev(self, "memory test failed\n"); |
490 | return; | | 488 | return; |
491 | } | | 489 | } |
492 | | | 490 | |
493 | /* Establish interrupt handler. */ | | 491 | /* Establish interrupt handler. */ |
494 | esc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq[0].ir_irq, | | 492 | esc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq[0].ir_irq, |
495 | IST_EDGE, IPL_NET, dp8390_intr, sc); | | 493 | IST_EDGE, IPL_NET, dp8390_intr, sc); |
496 | if (esc->sc_ih == NULL) | | 494 | if (esc->sc_ih == NULL) |
497 | aprint_error_dev(self, "can't establish interrupt\n"); | | 495 | aprint_error_dev(self, "can't establish interrupt\n"); |
498 | } | | 496 | } |
499 | | | 497 | |
500 | int | | 498 | int |
501 | ec_fake_test_mem(struct dp8390_softc *sc) | | 499 | ec_fake_test_mem(struct dp8390_softc *sc) |
502 | { | | 500 | { |
503 | | | 501 | |
504 | /* | | 502 | /* |
505 | * We have to do this after we initialize the GA, but we | | 503 | * We have to do this after we initialize the GA, but we |
506 | * have to do that after calling dp8390_config(), which | | 504 | * have to do that after calling dp8390_config(), which |
507 | * wants to test memory. Put this noop here, and then | | 505 | * wants to test memory. Put this noop here, and then |
508 | * actually test memory later. | | 506 | * actually test memory later. |
509 | */ | | 507 | */ |
510 | return (0); | | 508 | return (0); |
511 | } | | 509 | } |
512 | | | 510 | |
513 | int | | 511 | int |
514 | ec_test_mem(struct dp8390_softc *sc) | | 512 | ec_test_mem(struct dp8390_softc *sc) |
515 | { | | 513 | { |
516 | struct ec_softc *esc = (struct ec_softc *)sc; | | 514 | struct ec_softc *esc = (struct ec_softc *)sc; |
517 | bus_space_tag_t memt = sc->sc_buft; | | 515 | bus_space_tag_t memt = sc->sc_buft; |
518 | bus_space_handle_t memh = sc->sc_bufh; | | 516 | bus_space_handle_t memh = sc->sc_bufh; |
519 | bus_size_t memsize = sc->mem_size; | | 517 | bus_size_t memsize = sc->mem_size; |
520 | int i; | | 518 | int i; |
521 | | | 519 | |
522 | if (esc->sc_16bitp) | | 520 | if (esc->sc_16bitp) |
523 | bus_space_set_region_2(memt, memh, 0, 0, memsize >> 1); | | 521 | bus_space_set_region_2(memt, memh, 0, 0, memsize >> 1); |
524 | else | | 522 | else |
525 | bus_space_set_region_1(memt, memh, 0, 0, memsize); | | 523 | bus_space_set_region_1(memt, memh, 0, 0, memsize); |
526 | | | 524 | |
527 | if (esc->sc_16bitp) { | | 525 | if (esc->sc_16bitp) { |
528 | for (i = 0; i < memsize; i += 2) { | | 526 | for (i = 0; i < memsize; i += 2) { |
529 | if (bus_space_read_2(memt, memh, i) != 0) | | 527 | if (bus_space_read_2(memt, memh, i) != 0) |
530 | goto fail; | | 528 | goto fail; |
531 | } | | 529 | } |
532 | } else { | | 530 | } else { |
533 | for (i = 0; i < memsize; i++) { | | 531 | for (i = 0; i < memsize; i++) { |
534 | if (bus_space_read_1(memt, memh, i) != 0) | | 532 | if (bus_space_read_1(memt, memh, i) != 0) |
535 | goto fail; | | 533 | goto fail; |
536 | } | | 534 | } |
537 | } | | 535 | } |
538 | | | 536 | |
539 | return (0); | | 537 | return (0); |
540 | | | 538 | |
541 | fail: | | 539 | fail: |
542 | aprint_error_dev(sc->sc_dev, | | 540 | aprint_error_dev(sc->sc_dev, |
543 | "failed to clear shared memory at offset 0x%x\n", i); | | 541 | "failed to clear shared memory at offset 0x%x\n", i); |
544 | return (1); | | 542 | return (1); |
545 | } | | 543 | } |
546 | | | 544 | |
547 | /* | | 545 | /* |
548 | * Given a NIC memory source address and a host memory destination address, | | 546 | * Given a NIC memory source address and a host memory destination address, |
549 | * copy 'len' from NIC to host using shared memory. The 'len' is rounded | | 547 | * copy 'len' from NIC to host using shared memory. The 'len' is rounded |
550 | * up to a word - ok as long as mbufs are word-sized. | | 548 | * up to a word - ok as long as mbufs are word-sized. |
551 | */ | | 549 | */ |
552 | inline void | | 550 | static inline void |
553 | ec_readmem(struct ec_softc *esc, int from, uint8_t *to, int len) | | 551 | ec_readmem(struct ec_softc *esc, int from, uint8_t *to, int len) |
554 | { | | 552 | { |
555 | bus_space_tag_t memt = esc->sc_dp8390.sc_buft; | | 553 | bus_space_tag_t memt = esc->sc_dp8390.sc_buft; |
556 | bus_space_handle_t memh = esc->sc_dp8390.sc_bufh; | | 554 | bus_space_handle_t memh = esc->sc_dp8390.sc_bufh; |
557 | | | 555 | |
558 | if (len & 1) | | 556 | if (len & 1) |
559 | ++len; | | 557 | ++len; |
560 | | | 558 | |
561 | if (esc->sc_16bitp) | | 559 | if (esc->sc_16bitp) |
562 | bus_space_read_region_2(memt, memh, from, (u_int16_t *)to, | | 560 | bus_space_read_region_2(memt, memh, from, (u_int16_t *)to, |
563 | len >> 1); | | 561 | len >> 1); |
564 | else | | 562 | else |
565 | bus_space_read_region_1(memt, memh, from, to, len); | | 563 | bus_space_read_region_1(memt, memh, from, to, len); |
566 | } | | 564 | } |
567 | | | 565 | |
568 | int | | 566 | int |
569 | ec_write_mbuf(struct dp8390_softc *sc, struct mbuf *m, int buf) | | 567 | ec_write_mbuf(struct dp8390_softc *sc, struct mbuf *m, int buf) |
570 | { | | 568 | { |
571 | struct ec_softc *esc = (struct ec_softc *)sc; | | 569 | struct ec_softc *esc = (struct ec_softc *)sc; |
572 | bus_space_tag_t asict = esc->sc_asict; | | 570 | bus_space_tag_t asict = esc->sc_asict; |
573 | bus_space_handle_t asich = esc->sc_asich; | | 571 | bus_space_handle_t asich = esc->sc_asich; |
574 | bus_space_tag_t memt = esc->sc_dp8390.sc_buft; | | 572 | bus_space_tag_t memt = esc->sc_dp8390.sc_buft; |
575 | bus_space_handle_t memh = esc->sc_dp8390.sc_bufh; | | 573 | bus_space_handle_t memh = esc->sc_dp8390.sc_bufh; |
576 | u_int8_t *data, savebyte[2]; | | 574 | u_int8_t *data, savebyte[2]; |
577 | int savelen, len, leftover; | | 575 | int savelen, len, leftover; |
578 | #ifdef DIAGNOSTIC | | 576 | #ifdef DIAGNOSTIC |
579 | u_int8_t *lim; | | 577 | u_int8_t *lim; |
580 | #endif | | 578 | #endif |
581 | | | 579 | |
582 | savelen = m->m_pkthdr.len; | | 580 | savelen = m->m_pkthdr.len; |
583 | | | 581 | |
584 | /* | | 582 | /* |
585 | * 8-bit boards are simple: we're already in the correct | | 583 | * 8-bit boards are simple: we're already in the correct |
586 | * page, and no alignment tricks are necessary. | | 584 | * page, and no alignment tricks are necessary. |
587 | */ | | 585 | */ |
588 | if (esc->sc_16bitp == 0) { | | 586 | if (esc->sc_16bitp == 0) { |
589 | for (; m != NULL; buf += m->m_len, m = m->m_next) | | 587 | for (; m != NULL; buf += m->m_len, m = m->m_next) |
590 | bus_space_write_region_1(memt, memh, buf, | | 588 | bus_space_write_region_1(memt, memh, buf, |
591 | mtod(m, u_int8_t *), m->m_len); | | 589 | mtod(m, u_int8_t *), m->m_len); |
592 | if (savelen < ETHER_MIN_LEN - ETHER_CRC_LEN) { | | 590 | if (savelen < ETHER_MIN_LEN - ETHER_CRC_LEN) { |
593 | bus_space_set_region_1(memt, memh, buf, | | 591 | bus_space_set_region_1(memt, memh, buf, |
594 | 0, ETHER_MIN_LEN - ETHER_CRC_LEN - savelen); | | 592 | 0, ETHER_MIN_LEN - ETHER_CRC_LEN - savelen); |
595 | savelen = ETHER_MIN_LEN - ETHER_CRC_LEN; | | 593 | savelen = ETHER_MIN_LEN - ETHER_CRC_LEN; |
596 | } | | 594 | } |
597 | return (savelen); | | 595 | return (savelen); |
598 | } | | 596 | } |
599 | | | 597 | |
600 | /* | | 598 | /* |
601 | * If it's a 16-bit board, we have transmit buffers | | 599 | * If it's a 16-bit board, we have transmit buffers |
602 | * in a different page; switch to it. | | 600 | * in a different page; switch to it. |
603 | */ | | 601 | */ |
604 | if (esc->sc_16bitp) | | 602 | if (esc->sc_16bitp) |
605 | bus_space_write_1(asict, asich, ELINK2_GACFR, | | 603 | bus_space_write_1(asict, asich, ELINK2_GACFR, |
606 | ELINK2_GACFR_RSEL); | | 604 | ELINK2_GACFR_RSEL); |
607 | | | 605 | |
608 | /* Start out with no leftover data. */ | | 606 | /* Start out with no leftover data. */ |
609 | leftover = 0; | | 607 | leftover = 0; |
610 | savebyte[0] = savebyte[1] = 0; | | 608 | savebyte[0] = savebyte[1] = 0; |
611 | | | 609 | |
612 | for (; m != NULL; m = m->m_next) { | | 610 | for (; m != NULL; m = m->m_next) { |
613 | len = m->m_len; | | 611 | len = m->m_len; |
614 | if (len == 0) | | 612 | if (len == 0) |
615 | continue; | | 613 | continue; |
616 | data = mtod(m, u_int8_t *); | | 614 | data = mtod(m, u_int8_t *); |
617 | #ifdef DIAGNOSTIC | | 615 | #ifdef DIAGNOSTIC |
618 | lim = data + len; | | 616 | lim = data + len; |
619 | #endif | | 617 | #endif |
620 | while (len > 0) { | | 618 | while (len > 0) { |
621 | if (leftover) { | | 619 | if (leftover) { |
622 | /* | | 620 | /* |
623 | * Data left over (from mbuf or realignment). | | 621 | * Data left over (from mbuf or realignment). |
624 | * Buffer the next byte, and write it and | | 622 | * Buffer the next byte, and write it and |
625 | * the leftover data out. | | 623 | * the leftover data out. |
626 | */ | | 624 | */ |
627 | savebyte[1] = *data++; | | 625 | savebyte[1] = *data++; |
628 | len--; | | 626 | len--; |
629 | bus_space_write_2(memt, memh, buf, | | 627 | bus_space_write_2(memt, memh, buf, |
630 | *(u_int16_t *)savebyte); | | 628 | *(u_int16_t *)savebyte); |
631 | buf += 2; | | 629 | buf += 2; |
632 | leftover = 0; | | 630 | leftover = 0; |
633 | } else if (BUS_SPACE_ALIGNED_POINTER(data, u_int16_t) | | 631 | } else if (BUS_SPACE_ALIGNED_POINTER(data, u_int16_t) |
634 | == 0) { | | 632 | == 0) { |
635 | /* | | 633 | /* |
636 | * Unaligned data; buffer the next byte. | | 634 | * Unaligned data; buffer the next byte. |
637 | */ | | 635 | */ |
638 | savebyte[0] = *data++; | | 636 | savebyte[0] = *data++; |
639 | len--; | | 637 | len--; |
640 | leftover = 1; | | 638 | leftover = 1; |
641 | } else { | | 639 | } else { |
642 | /* | | 640 | /* |
643 | * Aligned data; output contiguous words as | | 641 | * Aligned data; output contiguous words as |
644 | * much as we can, then buffer the remaining | | 642 | * much as we can, then buffer the remaining |
645 | * byte, if any. | | 643 | * byte, if any. |
646 | */ | | 644 | */ |
647 | leftover = len & 1; | | 645 | leftover = len & 1; |
648 | len &= ~1; | | 646 | len &= ~1; |
649 | bus_space_write_region_2(memt, memh, buf, | | 647 | bus_space_write_region_2(memt, memh, buf, |
650 | (u_int16_t *)data, len >> 1); | | 648 | (u_int16_t *)data, len >> 1); |
651 | data += len; | | 649 | data += len; |
652 | buf += len; | | 650 | buf += len; |
653 | if (leftover) | | 651 | if (leftover) |
654 | savebyte[0] = *data++; | | 652 | savebyte[0] = *data++; |
655 | len = 0; | | 653 | len = 0; |
656 | } | | 654 | } |
657 | } | | 655 | } |
658 | if (len < 0) | | 656 | if (len < 0) |
659 | panic("ec_write_mbuf: negative len"); | | 657 | panic("ec_write_mbuf: negative len"); |
660 | #ifdef DIAGNOSTIC | | 658 | #ifdef DIAGNOSTIC |
661 | if (data != lim) | | 659 | if (data != lim) |
662 | panic("ec_write_mbuf: data != lim"); | | 660 | panic("ec_write_mbuf: data != lim"); |
663 | #endif | | 661 | #endif |
664 | } | | 662 | } |
665 | if (leftover) { | | 663 | if (leftover) { |
666 | savebyte[1] = 0; | | 664 | savebyte[1] = 0; |
667 | bus_space_write_2(memt, memh, buf, *(u_int16_t *)savebyte); | | 665 | bus_space_write_2(memt, memh, buf, *(u_int16_t *)savebyte); |
668 | buf += 2; | | 666 | buf += 2; |
669 | } | | 667 | } |
670 | if (savelen < ETHER_MIN_LEN - ETHER_CRC_LEN) { | | 668 | if (savelen < ETHER_MIN_LEN - ETHER_CRC_LEN) { |
671 | bus_space_set_region_2(memt, memh, buf, | | 669 | bus_space_set_region_2(memt, memh, buf, |
672 | 0, (ETHER_MIN_LEN - ETHER_CRC_LEN - savelen) >> 1); | | 670 | 0, (ETHER_MIN_LEN - ETHER_CRC_LEN - savelen) >> 1); |
673 | savelen = ETHER_MIN_LEN - ETHER_CRC_LEN; | | 671 | savelen = ETHER_MIN_LEN - ETHER_CRC_LEN; |
674 | } | | 672 | } |
675 | | | 673 | |
676 | /* | | 674 | /* |
677 | * Switch back to receive page. | | 675 | * Switch back to receive page. |
678 | */ | | 676 | */ |
679 | if (esc->sc_16bitp) | | 677 | if (esc->sc_16bitp) |
680 | bus_space_write_1(asict, asich, ELINK2_GACFR, | | 678 | bus_space_write_1(asict, asich, ELINK2_GACFR, |
681 | ELINK2_GACFR_RSEL | ELINK2_GACFR_MBS0); | | 679 | ELINK2_GACFR_RSEL | ELINK2_GACFR_MBS0); |
682 | | | 680 | |
683 | return (savelen); | | 681 | return (savelen); |
684 | } | | 682 | } |
685 | | | 683 | |
686 | int | | 684 | int |
687 | ec_ring_copy(struct dp8390_softc *sc, int src, void *dst, u_short amount) | | 685 | ec_ring_copy(struct dp8390_softc *sc, int src, void *dst, u_short amount) |
688 | { | | 686 | { |
689 | struct ec_softc *esc = (struct ec_softc *)sc; | | 687 | struct ec_softc *esc = (struct ec_softc *)sc; |
690 | u_short tmp_amount; | | 688 | u_short tmp_amount; |
691 | | | 689 | |
692 | /* Does copy wrap to lower addr in ring buffer? */ | | 690 | /* Does copy wrap to lower addr in ring buffer? */ |
693 | if (src + amount > sc->mem_end) { | | 691 | if (src + amount > sc->mem_end) { |
694 | tmp_amount = sc->mem_end - src; | | 692 | tmp_amount = sc->mem_end - src; |
695 | | | 693 | |
696 | /* Copy amount up to end of NIC memory. */ | | 694 | /* Copy amount up to end of NIC memory. */ |
697 | ec_readmem(esc, src, dst, tmp_amount); | | 695 | ec_readmem(esc, src, dst, tmp_amount); |
698 | | | 696 | |
699 | amount -= tmp_amount; | | 697 | amount -= tmp_amount; |
700 | src = sc->mem_ring; | | 698 | src = sc->mem_ring; |
701 | dst = (char *)dst + tmp_amount; | | 699 | dst = (char *)dst + tmp_amount; |
702 | } | | 700 | } |
703 | | | 701 | |
704 | ec_readmem(esc, src, dst, amount); | | 702 | ec_readmem(esc, src, dst, amount); |
705 | | | 703 | |
706 | return (src + amount); | | 704 | return (src + amount); |
707 | } | | 705 | } |
708 | | | 706 | |
709 | void | | 707 | void |
710 | ec_read_hdr(struct dp8390_softc *sc, int packet_ptr, | | 708 | ec_read_hdr(struct dp8390_softc *sc, int packet_ptr, |
711 | struct dp8390_ring *packet_hdrp) | | 709 | struct dp8390_ring *packet_hdrp) |
712 | { | | 710 | { |
713 | struct ec_softc *esc = (struct ec_softc *)sc; | | 711 | struct ec_softc *esc = (struct ec_softc *)sc; |
714 | | | 712 | |
715 | ec_readmem(esc, packet_ptr, (u_int8_t *)packet_hdrp, | | 713 | ec_readmem(esc, packet_ptr, (u_int8_t *)packet_hdrp, |
716 | sizeof(struct dp8390_ring)); | | 714 | sizeof(struct dp8390_ring)); |
717 | #if BYTE_ORDER == BIG_ENDIAN | | 715 | #if BYTE_ORDER == BIG_ENDIAN |
718 | packet_hdrp->count = bswap16(packet_hdrp->count); | | 716 | packet_hdrp->count = bswap16(packet_hdrp->count); |
719 | #endif | | 717 | #endif |
720 | } | | 718 | } |
721 | | | 719 | |
722 | void | | 720 | void |
723 | ec_media_init(struct dp8390_softc *sc) | | 721 | ec_media_init(struct dp8390_softc *sc) |
724 | { | | 722 | { |
725 | | | 723 | |
726 | ifmedia_init(&sc->sc_media, 0, dp8390_mediachange, dp8390_mediastatus); | | 724 | ifmedia_init(&sc->sc_media, 0, dp8390_mediachange, dp8390_mediastatus); |
727 | ifmedia_add(&sc->sc_media, IFM_ETHER|IFM_10_2, 0, NULL); | | 725 | ifmedia_add(&sc->sc_media, IFM_ETHER|IFM_10_2, 0, NULL); |
728 | ifmedia_add(&sc->sc_media, IFM_ETHER|IFM_10_5, 0, NULL); | | 726 | ifmedia_add(&sc->sc_media, IFM_ETHER|IFM_10_5, 0, NULL); |
729 | ifmedia_set(&sc->sc_media, IFM_ETHER|IFM_10_2); | | 727 | ifmedia_set(&sc->sc_media, IFM_ETHER|IFM_10_2); |
730 | } | | 728 | } |
731 | | | 729 | |
732 | int | | 730 | int |
733 | ec_mediachange(struct dp8390_softc *sc) | | 731 | ec_mediachange(struct dp8390_softc *sc) |
734 | { | | 732 | { |
735 | struct ec_softc *esc = (struct ec_softc *)sc; | | 733 | struct ec_softc *esc = (struct ec_softc *)sc; |
736 | struct ifmedia *ifm = &sc->sc_media; | | 734 | struct ifmedia *ifm = &sc->sc_media; |
737 | | | 735 | |
738 | return (ec_set_media(esc, ifm->ifm_media)); | | 736 | return (ec_set_media(esc, ifm->ifm_media)); |
739 | } | | 737 | } |
740 | | | 738 | |
741 | void | | 739 | void |
742 | ec_mediastatus(struct dp8390_softc *sc, struct ifmediareq *ifmr) | | 740 | ec_mediastatus(struct dp8390_softc *sc, struct ifmediareq *ifmr) |
743 | { | | 741 | { |
744 | struct ifmedia *ifm = &sc->sc_media; | | 742 | struct ifmedia *ifm = &sc->sc_media; |
745 | | | 743 | |
746 | /* | | 744 | /* |
747 | * The currently selected media is always the active media. | | 745 | * The currently selected media is always the active media. |
748 | */ | | 746 | */ |
749 | ifmr->ifm_active = ifm->ifm_cur->ifm_media; | | 747 | ifmr->ifm_active = ifm->ifm_cur->ifm_media; |
750 | } | | 748 | } |
751 | | | 749 | |
752 | void | | 750 | void |
753 | ec_init_card(struct dp8390_softc *sc) | | 751 | ec_init_card(struct dp8390_softc *sc) |
754 | { | | 752 | { |
755 | struct ec_softc *esc = (struct ec_softc *)sc; | | 753 | struct ec_softc *esc = (struct ec_softc *)sc; |
756 | struct ifmedia *ifm = &sc->sc_media; | | 754 | struct ifmedia *ifm = &sc->sc_media; |
757 | | | 755 | |
758 | (void) ec_set_media(esc, ifm->ifm_cur->ifm_media); | | 756 | (void) ec_set_media(esc, ifm->ifm_cur->ifm_media); |
759 | } | | 757 | } |
760 | | | 758 | |
761 | int | | 759 | int |
762 | ec_set_media(struct ec_softc *esc, int media) | | 760 | ec_set_media(struct ec_softc *esc, int media) |
763 | { | | 761 | { |
764 | u_int8_t new; | | 762 | u_int8_t new; |
765 | | | 763 | |
766 | if (IFM_TYPE(media) != IFM_ETHER) | | 764 | if (IFM_TYPE(media) != IFM_ETHER) |
767 | return (EINVAL); | | 765 | return (EINVAL); |
768 | | | 766 | |
769 | switch (IFM_SUBTYPE(media)) { | | 767 | switch (IFM_SUBTYPE(media)) { |
770 | case IFM_10_2: | | 768 | case IFM_10_2: |
771 | new = ELINK2_CR_XSEL; | | 769 | new = ELINK2_CR_XSEL; |
772 | break; | | 770 | break; |
773 | | | 771 | |
774 | case IFM_10_5: | | 772 | case IFM_10_5: |
775 | new = 0; | | 773 | new = 0; |
776 | break; | | 774 | break; |
777 | | | 775 | |
778 | default: | | 776 | default: |
779 | return (EINVAL); | | 777 | return (EINVAL); |
780 | } | | 778 | } |
781 | | | 779 | |
782 | bus_space_write_1(esc->sc_asict, esc->sc_asich, ELINK2_CR, new); | | 780 | bus_space_write_1(esc->sc_asict, esc->sc_asich, ELINK2_CR, new); |
783 | return (0); | | 781 | return (0); |
784 | } | | 782 | } |