cs89x0isa.c revision 1.1
1
2/* isa dma routines for cs89x0 */
3
4#include <sys/param.h>
5#include <sys/systm.h>
6#include <sys/mbuf.h>
7#include <sys/socket.h>
8#include <sys/device.h>
9
10#include "rnd.h"
11#if NRND > 0
12#include <sys/rnd.h>
13#endif
14
15#include <net/if.h>
16#include <net/if_ether.h>
17#include <net/if_media.h>
18
19#include <machine/bus.h>
20
21#include <dev/isa/isareg.h>
22#include <dev/isa/isavar.h>
23#include <dev/isa/isadmavar.h>
24
25#include <dev/ic/cs89x0reg.h>
26#include <dev/ic/cs89x0var.h>
27#include <dev/isa/cs89x0isavar.h>
28
29#define DMA_STATUS_BITS 0x0007	/* bit masks for checking DMA status */
30#define DMA_STATUS_OK 0x0004
31
32void
33cs_isa_dma_attach(struct cs_softc *sc)
34{
35	struct cs_softc_isa *isc = (void *)sc;
36
37	if (isc->sc_drq == ISACF_DRQ_DEFAULT)
38		printf("%s: DMA channel unspecified, not using DMA\n",
39		    sc->sc_dev.dv_xname);
40	else if (isc->sc_drq < 5 || isc->sc_drq > 7)
41		printf("%s: invalid DMA channel, not using DMA\n",
42		    sc->sc_dev.dv_xname);
43	else {
44		bus_size_t maxsize;
45		bus_addr_t dma_addr;
46
47		maxsize = isa_dmamaxsize(isc->sc_ic, isc->sc_drq);
48		if (maxsize < CS8900_DMASIZE) {
49			printf("%s: max DMA size %lu is less than required %d\n",
50			    sc->sc_dev.dv_xname, (u_long)maxsize,
51			    CS8900_DMASIZE);
52			goto after_dma_block;
53		}
54
55		if (isa_dmamap_create(isc->sc_ic, isc->sc_drq,
56		    CS8900_DMASIZE, BUS_DMA_NOWAIT) != 0) {
57			printf("%s: unable to create ISA DMA map\n",
58			    sc->sc_dev.dv_xname);
59			goto after_dma_block;
60		}
61		if (isa_dmamem_alloc(isc->sc_ic, isc->sc_drq,
62		    CS8900_DMASIZE, &dma_addr, BUS_DMA_NOWAIT) != 0) {
63			printf("%s: unable to allocate DMA buffer\n",
64			    sc->sc_dev.dv_xname);
65			goto after_dma_block;
66		}
67		if (isa_dmamem_map(isc->sc_ic, isc->sc_drq, dma_addr,
68		    CS8900_DMASIZE, &isc->sc_dmabase,
69		       BUS_DMA_NOWAIT | BUS_DMA_COHERENT /* XXX */ ) != 0) {
70			printf("%s: unable to map DMA buffer\n",
71			    sc->sc_dev.dv_xname);
72			isa_dmamem_free(isc->sc_ic, isc->sc_drq, dma_addr,
73			    CS8900_DMASIZE);
74			goto after_dma_block;
75		}
76
77		isc->sc_dmasize = CS8900_DMASIZE;
78		sc->sc_cfgflags |= CFGFLG_DMA_MODE;
79		isc->sc_dmaaddr = dma_addr;
80after_dma_block:
81	}
82}
83
84void cs_isa_dma_chipinit(struct cs_softc *sc)
85{
86	struct cs_softc_isa *isc = (void *)sc;
87
88	if (sc->sc_cfgflags & CFGFLG_DMA_MODE) {
89		/*
90		 * First we program the DMA controller and ensure the memory
91		 * buffer is valid. If it isn't then we just go on without
92		 * DMA.
93		 */
94		if (isa_dmastart(isc->sc_ic, isc->sc_drq, isc->sc_dmabase,
95		    isc->sc_dmasize, NULL, DMAMODE_READ | DMAMODE_LOOPDEMAND,
96		    BUS_DMA_NOWAIT)) {
97			/* XXX XXX XXX */
98			panic("%s: unable to start DMA\n", sc->sc_dev.dv_xname);
99		}
100		isc->sc_dmacur = isc->sc_dmabase;
101
102		/* interrupt when a DMA'd frame is received */
103		CS_WRITE_PACKET_PAGE(sc, PKTPG_RX_CFG,
104		    RX_CFG_ALL_IE | RX_CFG_RX_DMA_ONLY);
105
106		/*
107		 * set the DMA burst bit so we don't tie up the bus for too
108		 * long.
109		 */
110		if (isc->sc_dmasize == 16384) {
111			CS_WRITE_PACKET_PAGE(sc, PKTPG_BUS_CTL,
112			    ((CS_READ_PACKET_PAGE(sc, PKTPG_BUS_CTL) &
113			     ~BUS_CTL_DMA_SIZE) | BUS_CTL_DMA_BURST));
114		} else { /* use 64K */
115			CS_WRITE_PACKET_PAGE(sc, PKTPG_BUS_CTL,
116			    CS_READ_PACKET_PAGE(sc, PKTPG_BUS_CTL) |
117			     BUS_CTL_DMA_SIZE | BUS_CTL_DMA_BURST);
118		}
119
120		CS_WRITE_PACKET_PAGE(sc, PKTPG_DMA_CHANNEL, isc->sc_drq - 5);
121	}
122}
123
124void cs_process_rx_dma(struct cs_softc *sc)
125{
126	struct cs_softc_isa *isc = (void *)sc;
127	struct ifnet *ifp;
128	u_int16_t num_dma_frames;
129	u_int16_t pkt_length;
130	u_int16_t status;
131	u_int to_copy;
132	char *dma_mem_ptr;
133	struct mbuf *m;
134	u_char *pBuff;
135	int pad;
136
137	/* initialise the pointers */
138	ifp = &sc->sc_ethercom.ec_if;
139
140	/* Read the number of frames DMAed. */
141	num_dma_frames = CS_READ_PACKET_PAGE(sc, PKTPG_DMA_FRAME_COUNT);
142	num_dma_frames &= (u_int16_t) (0x0fff);
143
144	/*
145	 * Loop till number of DMA frames ready to read is zero. After
146	 * reading the frame out of memory we must check if any have been
147	 * received while we were processing
148	 */
149	while (num_dma_frames != 0) {
150		dma_mem_ptr = isc->sc_dmacur;
151
152		/*
153		 * process all of the dma frames in memory
154		 *
155		 * This loop relies on the dma_mem_ptr variable being set to the
156		 * next frames start address.
157		 */
158		for (; num_dma_frames > 0; num_dma_frames--) {
159
160			/*
161			 * Get the length and status of the packet. Only the
162			 * status is guarenteed to be at dma_mem_ptr, ie need
163			 * to check for wraparound before reading the length
164			 */
165			status = *((unsigned short *) dma_mem_ptr)++;
166			if (dma_mem_ptr > (isc->sc_dmabase + isc->sc_dmasize)) {
167				dma_mem_ptr = isc->sc_dmabase;
168			}
169			pkt_length = *((unsigned short *) dma_mem_ptr)++;
170
171			/* Do some sanity checks on the length and status. */
172			if ((pkt_length > ETHER_MAX_LEN) ||
173			    ((status & DMA_STATUS_BITS) != DMA_STATUS_OK)) {
174				/*
175				 * the SCO driver kills the adapter in this
176				 * situation
177				 */
178				/*
179				 * should increment the error count and reset
180				 * the dma operation.
181				 */
182				printf("%s: cs_process_rx_dma: DMA buffer out of sync about to reset\n",
183				    sc->sc_dev.dv_xname);
184				ifp->if_ierrors++;
185
186				/* skip the rest of the DMA buffer */
187				isa_dmaabort(isc->sc_ic, isc->sc_drq);
188
189				/* now reset the chip and reinitialise */
190				cs_init(&sc->sc_ethercom.ec_if);
191				return;
192			}
193			/* Check the status of the received packet. */
194			if (status & RX_EVENT_RX_OK) {
195				/* get a new mbuf */
196				MGETHDR(m, M_DONTWAIT, MT_DATA);
197				if (m == 0) {
198					printf("%s: cs_process_rx_dma: unable to allocate mbuf\n",
199					    sc->sc_dev.dv_xname);
200					ifp->if_ierrors++;
201					/*
202					 * couldn't allocate an mbuf so
203					 * things are not good, may as well
204					 * drop all the packets I think.
205					 */
206					CS_READ_PACKET_PAGE(sc,
207					    PKTPG_DMA_FRAME_COUNT);
208
209					/* now reset DMA operation */
210					isa_dmaabort(isc->sc_ic, isc->sc_drq);
211
212					/*
213					 * now reset the chip and
214					 * reinitialise
215					 */
216					cs_init(&sc->sc_ethercom.ec_if);
217					return;
218				}
219				/*
220				 * save processing by always using a mbuf
221				 * cluster, guarenteed to fit packet
222				 */
223				MCLGET(m, M_DONTWAIT);
224				if ((m->m_flags & M_EXT) == 0) {
225					/* couldn't allocate an mbuf cluster */
226					printf("%s: cs_process_rx_dma: unable to allocate a cluster\n",
227					    sc->sc_dev.dv_xname);
228					m_freem(m);
229
230					/* skip the frame */
231					CS_READ_PACKET_PAGE(sc, PKTPG_DMA_FRAME_COUNT);
232					isa_dmaabort(isc->sc_ic, isc->sc_drq);
233
234					/*
235					 * now reset the chip and
236					 * reinitialise
237					 */
238					cs_init(&sc->sc_ethercom.ec_if);
239					return;
240				}
241				m->m_pkthdr.rcvif = ifp;
242				m->m_pkthdr.len = pkt_length;
243				m->m_len = pkt_length;
244
245				/*
246				 * align ip header on word boundary for
247				 * ipintr
248				 */
249				pad = ALIGN(sizeof(struct ether_header)) -
250				    sizeof(struct ether_header);
251				m->m_data += pad;
252
253				/*
254				 * set up the buffer pointer to point to the
255				 * data area
256				 */
257				pBuff = mtod(m, char *);
258
259				/*
260				 * Read the frame into free_pktbuf
261				 * The buffer is circular buffer, either
262				 * 16K or 64K in length.
263				 *
264				 * need to check where the end of the buffer
265				 * is and go back to the start.
266				 */
267				if ((dma_mem_ptr + pkt_length) <
268				    (isc->sc_dmabase + isc->sc_dmasize)) {
269					/*
270					 * No wrap around. Copy the frame
271					 * header
272					 */
273					memcpy(pBuff, dma_mem_ptr, pkt_length);
274					dma_mem_ptr += pkt_length;
275				} else {
276					to_copy = (u_int)
277					    ((isc->sc_dmabase + isc->sc_dmasize) -
278					    dma_mem_ptr);
279
280					/* Copy the first half of the frame. */
281					memcpy(pBuff, dma_mem_ptr, to_copy);
282					pBuff += to_copy;
283
284					/*
285		                         * Rest of the frame is to be read
286		                         * from the first byte of the DMA
287		                         * memory.
288		                         */
289					/*
290					 * Get the number of bytes leftout in
291					 * the frame.
292					 */
293					to_copy = pkt_length - to_copy;
294
295					dma_mem_ptr = isc->sc_dmabase;
296
297					/* Copy rest of the frame. */
298					memcpy(pBuff, dma_mem_ptr, to_copy);
299					dma_mem_ptr += to_copy;
300				}
301
302				cs_ether_input(sc, m);
303			}
304			/* (status & RX_OK) */
305			else {
306				/* the frame was not received OK */
307				/* Increment the input error count */
308				ifp->if_ierrors++;
309
310				/*
311				 * If debugging is enabled then log error
312				 * messages if we got any.
313				 */
314				if ((ifp->if_flags & IFF_DEBUG) &&
315				    status != REG_NUM_RX_EVENT)
316					cs_print_rx_errors(sc, status);
317			}
318			/*
319			 * now update the current frame pointer. the
320			 * dma_mem_ptr should point to the next packet to be
321			 * received, without the alignment considerations.
322			 *
323			 * The cs8900 pads all frames to start at the next 32bit
324			 * aligned addres. hence we need to pad our offset
325			 * pointer.
326			 */
327			dma_mem_ptr += 3;
328			dma_mem_ptr = (char *)
329			    ((long) dma_mem_ptr & 0xfffffffc);
330			if (dma_mem_ptr < (isc->sc_dmabase + isc->sc_dmasize)) {
331				isc->sc_dmacur = dma_mem_ptr;
332			} else {
333				dma_mem_ptr = isc->sc_dmacur = isc->sc_dmabase;
334			}
335		} /* for all frames */
336		/* Read the number of frames DMAed again. */
337		num_dma_frames = CS_READ_PACKET_PAGE(sc, PKTPG_DMA_FRAME_COUNT);
338		num_dma_frames &= (u_int16_t) (0x0fff);
339	} /* while there are frames left */
340}
341