1 /* $NetBSD: if_mc_obio.c,v 1.16 2006/12/12 11:46:33 martin Exp $ */
4 * Copyright (c) 1997 David Huang <khym@azeotrope.org>
7 * Portions of this code are based on code by Denton Gentry <denny1@home.com>
8 * and Yanagisawa Takeshi <yanagisw@aa.ap.titech.ac.jp>.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 * Bus attachment and DMA routines for the mc driver (Centris/Quadra
33 * 660av and Quadra 840av onboard ethernet, based on the AMD Am79C940
34 * MACE ethernet chip). Also uses the PSC (Peripheral Subsystem
35 * Controller) for DMA to and from the MACE.
38 #include <sys/cdefs.h>
39 __KERNEL_RCSID(0, "$NetBSD: if_mc_obio.c,v 1.16 2006/12/12 11:46:33 martin Exp $");
43 #include <sys/param.h>
44 #include <sys/device.h>
45 #include <sys/malloc.h>
46 #include <sys/socket.h>
47 #include <sys/systm.h>
50 #include <net/if_ether.h>
52 #include <uvm/uvm_extern.h>
54 #include <machine/bus.h>
55 #include <machine/psc.h>
57 #include <mac68k/obio/obiovar.h>
58 #include <mac68k/dev/if_mcreg.h>
59 #include <mac68k/dev/if_mcvar.h>
61 #define MACE_REG_BASE 0x50F1C000
62 #define MACE_PROM_BASE 0x50F08000
64 hide
int mc_obio_match(struct device
*, struct cfdata
*, void *);
65 hide
void mc_obio_attach(struct device
*, struct device
*, void *);
66 hide
void mc_obio_init(struct mc_softc
*);
67 hide
void mc_obio_put(struct mc_softc
*, u_int
);
68 hide
int mc_dmaintr(void *);
69 hide
void mc_reset_rxdma(struct mc_softc
*);
70 hide
void mc_reset_rxdma_set(struct mc_softc
*, int);
71 hide
void mc_reset_txdma(struct mc_softc
*);
72 hide
int mc_obio_getaddr(struct mc_softc
*, u_int8_t
*);
74 CFATTACH_DECL(mc_obio
, sizeof(struct mc_softc
),
75 mc_obio_match
, mc_obio_attach
, NULL
, NULL
);
78 mc_obio_match(struct device
*parent
, struct cfdata
*cf
, void *aux
)
80 struct obio_attach_args
*oa
= aux
;
81 bus_space_handle_t bsh
;
84 if (current_mac_model
->class != MACH_CLASSAV
)
87 if (bus_space_map(oa
->oa_tag
, MACE_REG_BASE
, MC_REGSIZE
, 0, &bsh
))
91 * Make sure the MACE's I/O space is readable, and if it is,
92 * try to read the CHIPID register. A MACE will always have
93 * 0x?940, where the ? depends on the chip version.
95 if (mac68k_bus_space_probe(oa
->oa_tag
, bsh
, 0, 1)) {
96 if ((bus_space_read_1(
97 oa
->oa_tag
, bsh
, MACE_REG(MACE_CHIPIDL
)) == 0x40) &&
99 oa
->oa_tag
, bsh
, MACE_REG(MACE_CHIPIDH
)) & 0xf) == 9))
103 bus_space_unmap(oa
->oa_tag
, bsh
, MC_REGSIZE
);
109 mc_obio_attach(struct device
*parent
, struct device
*self
, void *aux
)
111 struct obio_attach_args
*oa
= (struct obio_attach_args
*)aux
;
112 struct mc_softc
*sc
= (void *)self
;
113 u_int8_t myaddr
[ETHER_ADDR_LEN
];
116 sc
->sc_regt
= oa
->oa_tag
;
117 sc
->sc_biucc
= XMTSP_64
;
118 sc
->sc_fifocc
= XMTFW_16
| RCVFW_64
| XMTFWU
| RCVFWU
|
120 sc
->sc_plscc
= PORTSEL_AUI
;
122 if (bus_space_map(sc
->sc_regt
, MACE_REG_BASE
, MC_REGSIZE
, 0,
124 printf(": failed to map space for MACE regs.\n");
128 if (mc_obio_getaddr(sc
, myaddr
)) {
129 printf(": failed to get MAC address.\n");
133 /* allocate memory for transmit and receive DMA buffers */
134 sc
->sc_dmat
= oa
->oa_dmat
;
135 if (bus_dmamem_alloc(sc
->sc_dmat
, 2 * 0x800, 0, 0, &sc
->sc_dmasegs_tx
,
136 1, &rsegs
, BUS_DMA_NOWAIT
) != 0) {
137 printf(": failed to allocate TX DMA buffers.\n");
141 if (bus_dmamem_map(sc
->sc_dmat
, &sc
->sc_dmasegs_tx
, rsegs
, 2 * 0x800,
142 (void*)&sc
->sc_txbuf
, BUS_DMA_NOWAIT
| BUS_DMA_COHERENT
) != 0) {
143 printf(": failed to map TX DMA buffers.\n");
147 if (bus_dmamem_alloc(sc
->sc_dmat
, MC_RXDMABUFS
* 0x800, 0, 0,
148 &sc
->sc_dmasegs_rx
, 1, &rsegs
, BUS_DMA_NOWAIT
) != 0) {
149 printf(": failed to allocate RX DMA buffers.\n");
153 if (bus_dmamem_map(sc
->sc_dmat
, &sc
->sc_dmasegs_rx
, rsegs
,
154 MC_RXDMABUFS
* 0x800, (void*)&sc
->sc_rxbuf
,
155 BUS_DMA_NOWAIT
| BUS_DMA_COHERENT
) != 0) {
156 printf(": failed to map RX DMA buffers.\n");
160 if (bus_dmamap_create(sc
->sc_dmat
, 2 * 0x800, 1, 2 * 0x800, 0,
161 BUS_DMA_NOWAIT
, &sc
->sc_dmam_tx
) != 0) {
162 printf(": failed to allocate TX DMA map.\n");
166 if (bus_dmamap_load(sc
->sc_dmat
, sc
->sc_dmam_tx
, sc
->sc_txbuf
,
167 2 * 0x800, NULL
, BUS_DMA_NOWAIT
) != 0) {
168 printf(": failed to map TX DMA mapping.\n");
172 if (bus_dmamap_create(sc
->sc_dmat
, MC_RXDMABUFS
* 0x800, 1,
173 MC_RXDMABUFS
* 0x800, 0, BUS_DMA_NOWAIT
, &sc
->sc_dmam_rx
) != 0) {
174 printf(": failed to allocate RX DMA map.\n");
178 if (bus_dmamap_load(sc
->sc_dmat
, sc
->sc_dmam_rx
, sc
->sc_rxbuf
,
179 MC_RXDMABUFS
* 0x800, NULL
, BUS_DMA_NOWAIT
) != 0) {
180 printf(": failed to map RX DMA mapping.\n");
184 sc
->sc_txbuf_phys
= sc
->sc_dmasegs_tx
.ds_addr
;
185 sc
->sc_rxbuf_phys
= sc
->sc_dmasegs_rx
.ds_addr
;
187 sc
->sc_bus_init
= mc_obio_init
;
188 sc
->sc_putpacket
= mc_obio_put
;
190 /* disable receive DMA */
191 psc_reg2(PSC_ENETRD_CTL
) = 0x8800;
192 psc_reg2(PSC_ENETRD_CTL
) = 0x1000;
193 psc_reg2(PSC_ENETRD_CMD
+ PSC_SET0
) = 0x1100;
194 psc_reg2(PSC_ENETRD_CMD
+ PSC_SET1
) = 0x1100;
196 /* disable transmit DMA */
197 psc_reg2(PSC_ENETWR_CTL
) = 0x8800;
198 psc_reg2(PSC_ENETWR_CTL
) = 0x1000;
199 psc_reg2(PSC_ENETWR_CMD
+ PSC_SET0
) = 0x1100;
200 psc_reg2(PSC_ENETWR_CMD
+ PSC_SET1
) = 0x1100;
202 /* install interrupt handlers */
203 add_psc_lev4_intr(PSCINTR_ENET_DMA
, mc_dmaintr
, sc
);
204 add_psc_lev3_intr(mcintr
, sc
);
206 /* enable MACE DMA interrupts */
207 psc_reg1(PSC_LEV4_IER
) = 0x80 | (1 << PSCINTR_ENET_DMA
);
209 /* don't know what this does */
210 psc_reg2(PSC_ENETWR_CTL
) = 0x9000;
211 psc_reg2(PSC_ENETRD_CTL
) = 0x9000;
212 psc_reg2(PSC_ENETWR_CTL
) = 0x0400;
213 psc_reg2(PSC_ENETRD_CTL
) = 0x0400;
215 /* enable MACE interrupts */
216 psc_reg1(PSC_LEV3_IER
) = 0x80 | (1 << PSCINTR_ENET
);
218 /* mcsetup returns 1 if something fails */
219 if (mcsetup(sc
, myaddr
)) {
220 /* disable interrupts */
221 psc_reg1(PSC_LEV4_IER
) = (1 << PSCINTR_ENET_DMA
);
222 psc_reg1(PSC_LEV3_IER
) = (1 << PSCINTR_ENET
);
223 /* remove interrupt handlers */
224 remove_psc_lev4_intr(PSCINTR_ENET_DMA
);
225 remove_psc_lev3_intr();
227 bus_space_unmap(sc
->sc_regt
, sc
->sc_regh
, MC_REGSIZE
);
232 /* Bus-specific initialization */
234 mc_obio_init(struct mc_softc
*sc
)
241 mc_obio_put(struct mc_softc
*sc
, u_int len
)
243 int offset
= sc
->sc_txset
== 0 ? 0 : 0x800;
245 bus_dmamap_sync(sc
->sc_dmat
, sc
->sc_dmam_tx
, offset
, 0x800,
246 BUS_DMASYNC_PREWRITE
);
247 psc_reg4(PSC_ENETWR_ADDR
+ sc
->sc_txset
) = sc
->sc_txbuf_phys
+ offset
;
248 psc_reg4(PSC_ENETWR_LEN
+ sc
->sc_txset
) = len
;
249 psc_reg2(PSC_ENETWR_CMD
+ sc
->sc_txset
) = 0x9800;
250 bus_dmamap_sync(sc
->sc_dmat
, sc
->sc_dmam_tx
, offset
, 0x800,
251 BUS_DMASYNC_POSTWRITE
);
253 sc
->sc_txset
^= 0x10;
257 * Interrupt handler for the MACE DMA completion interrupts
260 mc_dmaintr(void *arg
)
262 struct mc_softc
*sc
= arg
;
264 u_int32_t bufsleft
, which
;
268 * Not sure what this does... figure out if this interrupt is
271 while ((which
= psc_reg4(0x804)) != psc_reg4(0x804))
273 if ((which
& 0x60000000) == 0)
276 /* Get the read channel status */
277 status
= psc_reg2(PSC_ENETRD_CTL
);
278 if (status
& 0x2000) {
279 /* I think this is an exceptional condition. Reset the DMA */
282 printf("%s: resetting receive DMA channel (status 0x%04x)\n",
283 sc
->sc_dev
.dv_xname
, status
);
285 } else if (status
& 0x100) {
286 /* We've received some packets from the MACE */
289 /* Clear the interrupt */
290 psc_reg2(PSC_ENETRD_CMD
+ sc
->sc_rxset
) = 0x1100;
292 /* See how may receive buffers are left */
293 bufsleft
= psc_reg4(PSC_ENETRD_LEN
+ sc
->sc_rxset
);
294 head
= MC_RXDMABUFS
- bufsleft
;
296 #if 0 /* I don't think this should ever happen */
297 if (head
== sc
->sc_tail
) {
299 printf("%s: head == tail: suspending DMA?\n",
300 sc
->sc_dev
.dv_xname
);
302 psc_reg2(PSC_ENETRD_CMD
+ sc
->sc_rxset
) = 0x9000;
306 /* Loop through, processing each of the packets */
307 for (; sc
->sc_tail
< head
; sc
->sc_tail
++) {
308 offset
= sc
->sc_tail
* 0x800;
310 bus_dmamap_sync(sc
->sc_dmat
, sc
->sc_dmam_rx
,
311 PAGE_SIZE
+ offset
, 0x800,
312 BUS_DMASYNC_PREREAD
);
314 sc
->sc_rxframe
.rx_rcvcnt
= sc
->sc_rxbuf
[offset
];
315 sc
->sc_rxframe
.rx_rcvsts
= sc
->sc_rxbuf
[offset
+2];
316 sc
->sc_rxframe
.rx_rntpc
= sc
->sc_rxbuf
[offset
+4];
317 sc
->sc_rxframe
.rx_rcvcc
= sc
->sc_rxbuf
[offset
+6];
318 sc
->sc_rxframe
.rx_frame
= sc
->sc_rxbuf
+ offset
+ 16;
322 bus_dmamap_sync(sc
->sc_dmat
, sc
->sc_dmam_rx
,
323 PAGE_SIZE
+ offset
, 0x800,
324 BUS_DMASYNC_POSTREAD
);
328 * If we're out of buffers, reset this register set
329 * and switch to the other one. Otherwise, reactivate
333 mc_reset_rxdma_set(sc
, sc
->sc_rxset
);
334 sc
->sc_rxset
^= 0x10;
336 psc_reg2(PSC_ENETRD_CMD
+ sc
->sc_rxset
) = 0x9800;
339 /* Get the write channel status */
340 status
= psc_reg2(PSC_ENETWR_CTL
);
341 if (status
& 0x2000) {
342 /* I think this is an exceptional condition. Reset the DMA */
345 printf("%s: resetting transmit DMA channel (status 0x%04x)\n",
346 sc
->sc_dev
.dv_xname
, status
);
348 } else if (status
& 0x100) {
349 /* Clear the interrupt and switch register sets */
350 psc_reg2(PSC_ENETWR_CMD
+ sc
->sc_txseti
) = 0x100;
351 sc
->sc_txseti
^= 0x10;
359 mc_reset_rxdma(struct mc_softc
*sc
)
363 /* Disable receiver, reset the DMA channels */
364 maccc
= NIC_GET(sc
, MACE_MACCC
);
365 NIC_PUT(sc
, MACE_MACCC
, maccc
& ~ENRCV
);
366 psc_reg2(PSC_ENETRD_CTL
) = 0x8800;
367 mc_reset_rxdma_set(sc
, 0);
368 psc_reg2(PSC_ENETRD_CTL
) = 0x400;
370 psc_reg2(PSC_ENETRD_CTL
) = 0x8800;
371 mc_reset_rxdma_set(sc
, 0x10);
372 psc_reg2(PSC_ENETRD_CTL
) = 0x400;
374 /* Reenable receiver, reenable DMA */
375 NIC_PUT(sc
, MACE_MACCC
, maccc
);
378 psc_reg2(PSC_ENETRD_CMD
+ PSC_SET0
) = 0x9800;
379 psc_reg2(PSC_ENETRD_CMD
+ PSC_SET1
) = 0x9800;
383 mc_reset_rxdma_set(struct mc_softc
*sc
, int set
)
385 /* disable DMA while modifying the registers, then reenable DMA */
386 psc_reg2(PSC_ENETRD_CMD
+ set
) = 0x0100;
387 psc_reg4(PSC_ENETRD_ADDR
+ set
) = sc
->sc_rxbuf_phys
;
388 psc_reg4(PSC_ENETRD_LEN
+ set
) = MC_RXDMABUFS
;
389 psc_reg2(PSC_ENETRD_CMD
+ set
) = 0x9800;
394 mc_reset_txdma(struct mc_softc
*sc
)
398 psc_reg2(PSC_ENETWR_CTL
) = 0x8800;
399 maccc
= NIC_GET(sc
, MACE_MACCC
);
400 NIC_PUT(sc
, MACE_MACCC
, maccc
& ~ENXMT
);
401 sc
->sc_txset
= sc
->sc_txseti
= 0;
402 psc_reg2(PSC_ENETWR_CTL
) = 0x400;
403 NIC_PUT(sc
, MACE_MACCC
, maccc
);
407 mc_obio_getaddr(struct mc_softc
*sc
, u_int8_t
*lladdr
)
409 bus_space_handle_t bsh
;
412 if (bus_space_map(sc
->sc_regt
, MACE_PROM_BASE
, 8*16, 0, &bsh
)) {
413 printf(": failed to map space to read MACE address.\n%s",
414 sc
->sc_dev
.dv_xname
);
418 if (!mac68k_bus_space_probe(sc
->sc_regt
, bsh
, 0, 1)) {
419 bus_space_unmap(sc
->sc_regt
, bsh
, 8*16);
423 csum
= mc_get_enaddr(sc
->sc_regt
, bsh
, 1, lladdr
);
425 printf(": ethernet PROM checksum failed (0x%x != 0xff)\n%s",
426 (int)csum
, sc
->sc_dev
.dv_xname
);
428 bus_space_unmap(sc
->sc_regt
, bsh
, 8*16);
430 return (csum
== 0xff ? 0 : -1);