1 /* $NetBSD: if_le.c,v 1.17 2008/04/28 20:23:30 martin Exp $ */
4 * Copyright (c) 2009 Stephen M. Rumble
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 #include <sys/cdefs.h>
28 __KERNEL_RCSID(0, "$NetBSD: if_le.c,v 1.17 2008/04/28 20:23:30 martin Exp $");
33 #include <sys/param.h>
34 #include <sys/systm.h>
36 #include <sys/syslog.h>
37 #include <sys/socket.h>
38 #include <sys/device.h>
40 #include <uvm/uvm.h> // for uvm_pglistalloc
43 #include <net/if_ether.h>
44 #include <net/if_media.h>
47 #include <netinet/in.h>
48 #include <netinet/if_inarp.h>
51 #include <machine/cpu.h>
52 #include <machine/machtype.h>
54 #include <dev/ic/lancereg.h>
55 #include <dev/ic/lancevar.h>
56 #include <dev/ic/am7990reg.h>
57 #include <dev/ic/am7990var.h>
59 #include <dev/arcbios/arcbios.h>
60 #include <dev/arcbios/arcbiosvar.h>
62 #include <sgimips/ioc/oiocvar.h>
63 #include <sgimips/ioc/oiocreg.h>
65 #include <mips/include/cache.h>
67 #ifndef OIOC_LANCE_NPAGES
68 #define OIOC_LANCE_NPAGES 64 /* 256KB */
71 #if OIOC_LANCE_NPAGES > OIOC_ENET_NPGMAPS
72 #error OIOC_LANCE_NPAGES > OIOC_ENET_NPGMAPS (512)
76 * Ethernet software status per interface.
77 * The real stuff is in dev/ic/am7990var.h
78 * The really real stuff is in dev/ic/lancevar.h
80 * Lance is somewhat nasty MI code. We basically get:
82 * struct am7990_softc {
83 * struct lance_softc {
92 * So, we can cast any three to any other three, plus sc_dev->dv_private points
93 * back at the top (i.e. to le_softc, am7990_softc and lance_softc). Bloody
97 struct am7990_softc sc_am7990
; /* glue to MI code */
99 bus_space_tag_t sc_st
;
100 bus_space_handle_t sc_maph
; /* ioc<->lance page map regs */
101 bus_space_handle_t sc_rdph
; /* lance rdp */
102 bus_space_handle_t sc_raph
; /* lance rap */
105 static int le_match(device_t
, cfdata_t
, void *);
106 static void le_attach(device_t
, device_t
, void *);
108 CFATTACH_DECL_NEW(le
, sizeof(struct le_softc
),
109 le_match
, le_attach
, NULL
, NULL
);
111 #if defined(_KERNEL_OPT)
115 static void lewrcsr(struct lance_softc
*, uint16_t, uint16_t);
116 static uint16_t lerdcsr(struct lance_softc
*, uint16_t);
117 static void enaddr_aton(const char *, u_int8_t
*);
120 lewrcsr(struct lance_softc
*sc
, uint16_t port
, uint16_t val
)
122 struct le_softc
*lesc
= (struct le_softc
*)sc
;
123 bus_space_write_2(lesc
->sc_st
, lesc
->sc_raph
, 0, port
);
124 bus_space_write_2(lesc
->sc_st
, lesc
->sc_rdph
, 0, val
);
128 lerdcsr(struct lance_softc
*sc
, uint16_t port
)
130 struct le_softc
*lesc
= (struct le_softc
*)sc
;
131 bus_space_write_2(lesc
->sc_st
, lesc
->sc_raph
, 0, port
);
132 return (bus_space_read_2(lesc
->sc_st
, lesc
->sc_rdph
, 0));
136 * Always present on IP6 and IP10. IP4? Unknown.
139 le_match(device_t parent
, cfdata_t cf
, void *aux
)
141 struct oioc_attach_args
*oa
= aux
;
143 if (mach_type
== MACH_SGI_IP4
)
146 if (strcmp(oa
->oa_name
, cf
->cf_name
) == 0)
153 le_attach(device_t parent
, device_t self
, void *aux
)
155 extern paddr_t avail_start
, avail_end
;
157 struct le_softc
*lesc
= device_private(self
);
158 struct lance_softc
*sc
= &lesc
->sc_am7990
.lsc
;
159 struct oioc_attach_args
*oa
= aux
;
161 const char *enaddrstr
;
167 lesc
->sc_st
= oa
->oa_st
;
169 enaddrstr
= ARCBIOS
->GetEnvironmentVariable("eaddr");
170 if (enaddrstr
== NULL
) {
171 aprint_error(": failed to obtain MAC address\n");
175 if ((error
= bus_space_subregion(oa
->oa_st
, oa
->oa_sh
, OIOC_LANCE_RDP
,
176 OIOC_LANCE_RDP_SIZE
, &lesc
->sc_rdph
)) != 0) {
177 printf(": unable to map rdp reg, error=%d\n", error
);
181 if ((error
= bus_space_subregion(oa
->oa_st
, oa
->oa_sh
, OIOC_LANCE_RAP
,
182 OIOC_LANCE_RAP_SIZE
, &lesc
->sc_raph
)) != 0) {
183 printf(": unable to map rap reg, error=%d\n", error
);
187 if ((error
= bus_space_subregion(oa
->oa_st
, oa
->oa_sh
,
188 OIOC_ENET_PGMAP_BASE
, OIOC_ENET_PGMAP_SIZE
, &lesc
->sc_maph
)) != 0) {
189 printf(": unable to map rap reg, error=%d\n", error
);
193 /* Allocate a contiguous chunk of physical memory for the le buffer. */
194 error
= uvm_pglistalloc(OIOC_LANCE_NPAGES
* PAGE_SIZE
,
195 avail_start
, avail_end
, PAGE_SIZE
, 0, &mlist
, 1, 0);
197 aprint_error(": failed to allocate ioc<->lance buffer space, "
198 "error = %d\n", error
);
202 /* Use IOC to map the physical memory into the Ethernet chip's space. */
203 for (i
= 0; i
< OIOC_LANCE_NPAGES
; i
++) {
204 bus_space_write_2(lesc
->sc_st
,lesc
->sc_maph
,
205 OIOC_ENET_PGMAP_OFF(i
),
206 (VM_PAGE_TO_PHYS(mlist
.tqh_first
) >> PAGE_SHIFT
) + i
);
209 sc
->sc_mem
= (void *)MIPS_PHYS_TO_KSEG1(
210 (uint32_t)VM_PAGE_TO_PHYS(mlist
.tqh_first
));
211 sc
->sc_memsize
= OIOC_LANCE_NPAGES
* PAGE_SIZE
;
213 sc
->sc_conf3
= LE_C3_BSWP
;
215 enaddr_aton(enaddrstr
, enaddr
);
216 memcpy(sc
->sc_enaddr
, enaddr
, sizeof(sc
->sc_enaddr
));
218 if (cpu_intr_establish(oa
->oa_irq
, IPL_NET
, am7990_intr
, sc
) == NULL
) {
219 aprint_error(": failed to establish interrupt %d\n",oa
->oa_irq
);
223 sc
->sc_copytodesc
= lance_copytobuf_contig
;
224 sc
->sc_copyfromdesc
= lance_copyfrombuf_contig
;
225 sc
->sc_copytobuf
= lance_copytobuf_contig
;
226 sc
->sc_copyfrombuf
= lance_copyfrombuf_contig
;
227 sc
->sc_zerobuf
= lance_zerobuf_contig
;
229 sc
->sc_rdcsr
= lerdcsr
;
230 sc
->sc_wrcsr
= lewrcsr
;
231 sc
->sc_hwinit
= NULL
;
233 format_bytes(pbuf
, sizeof(pbuf
), OIOC_LANCE_NPAGES
* PAGE_SIZE
);
234 aprint_normal(": main memory used = %s\n", pbuf
);
235 aprint_normal("%s", device_xname(self
));
237 am7990_config(&lesc
->sc_am7990
);
242 uvm_pglistfree(&mlist
);
244 bus_space_unmap(oa
->oa_st
, oa
->oa_sh
, lesc
->sc_maph
);
246 bus_space_unmap(oa
->oa_st
, oa
->oa_sh
, lesc
->sc_raph
);
248 bus_space_unmap(oa
->oa_st
, oa
->oa_sh
, lesc
->sc_rdph
);
253 /* stolen from sgimips/hpc/if_sq.c */
255 enaddr_aton(const char *str
, u_int8_t
*eaddr
)
260 for (i
= 0; i
< ETHER_ADDR_LEN
; i
++) {
266 eaddr
[i
] = (c
- '0');
267 } else if (isxdigit(c
)) {
268 eaddr
[i
] = (toupper(c
) + 10 - 'A');
273 eaddr
[i
] = (eaddr
[i
] << 4) | (c
- '0');
274 } else if (isxdigit(c
)) {
275 eaddr
[i
] = (eaddr
[i
] << 4) | (toupper(c
) + 10 - 'A');