summaryrefslogtreecommitdiffstats
path: root/sys/dev/hatm/if_hatmvar.h
blob: d19fd0eabd742d1b828fb000f02bcb9c2ab36133 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
/*-
 * Copyright (c) 2001-2003
 *	Fraunhofer Institute for Open Communication Systems (FhG Fokus).
 * 	All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * Author: Hartmut Brandt <harti@freebsd.org>
 *
 * $FreeBSD$
 *
 * Fore HE driver for NATM
 */

/*
 * Debug statistics of the HE driver
 */
struct istats {
	uint32_t	tdprq_full;
	uint32_t	hbuf_error;
	uint32_t	crc_error;
	uint32_t	len_error;
	uint32_t	flow_closed;
	uint32_t	flow_drop;
	uint32_t	tpd_no_mem;
	uint32_t	rx_seg;
	uint32_t	empty_hbuf;
	uint32_t	short_aal5;
	uint32_t	badlen_aal5;
	uint32_t	bug_bad_isw;
	uint32_t	bug_no_irq_upd;
	uint32_t	itype_tbrq;
	uint32_t	itype_tpd;
	uint32_t	itype_rbps;
	uint32_t	itype_rbpl;
	uint32_t	itype_rbrq;
	uint32_t	itype_rbrqt;
	uint32_t	itype_unknown;
	uint32_t	itype_phys;
	uint32_t	itype_err;
	uint32_t	defrag;
	uint32_t	mcc;
	uint32_t	oec;
	uint32_t	dcc;
	uint32_t	cec;
	uint32_t	no_rcv_mbuf;
};

/* Card memory layout parameters */
#define HE_CONFIG_MEM_LAYOUT {						\
	{			/* 155 */				\
	  20,			/* cells_per_row */			\
	  1024,			/* bytes_per_row */			\
	  512,			/* r0_numrows */			\
	  1018,			/* tx_numrows */			\
	  512,			/* r1_numrows */			\
	  6,			/* r0_startrow */			\
	  2			/* cells_per_lbuf */			\
	}, {			/* 622 */				\
	  40,			/* cells_per_row */			\
	  2048,			/* bytes_per_row */			\
	  256,			/* r0_numrows */			\
	  512,			/* tx_numrows */			\
	  256,			/* r1_numrows */			\
	  0,			/* r0_startrow */			\
	  4			/* cells_per_lbuf */			\
	}								\
}

/*********************************************************************/
struct hatm_softc;

/*
 * A chunk of DMA-able memory
 */
struct dmamem {
	u_int		size;		/* in bytes */
	u_int		align;		/* alignement */
	bus_dma_tag_t	tag;		/* DMA tag */
	void		*base;		/* the memory */
	bus_addr_t	paddr;		/* physical address */
	bus_dmamap_t	map;		/* the MAP */
};

/*
 * RBP (Receive Buffer Pool) queue entry and queue.
 */
struct herbp {
	u_int		size;		/* RBP number of entries (power of two) */
	u_int		thresh;		/* interrupt treshold */
	uint32_t	bsize;		/* buffer size in bytes */
	u_int		offset;		/* free space at start for small bufs */
	uint32_t	mask;		/* mask for index */
	struct dmamem	mem;		/* the queue area */
	struct he_rbpen	*rbp;
	uint32_t	head, tail;	/* head and tail */
};

/*
 * RBRQ (Receive Buffer Return Queue) entry and queue.
 */
struct herbrq {
	u_int		size;		/* number of entries */
	u_int		thresh;		/* interrupt threshold */
	u_int		tout;		/* timeout value */
	u_int		pcnt;		/* packet count threshold */
	struct dmamem	mem;		/* memory */
	struct he_rbrqen *rbrq;
	uint32_t	head;		/* driver end */
};

/*
 * TPDRQ (Transmit Packet Descriptor Ready Queue) entry and queue
 */
struct hetpdrq {
	u_int		size;		/* number of entries */
	struct dmamem	mem;		/* memory */
	struct he_tpdrqen *tpdrq;
	u_int		head;		/* head (copy of adapter) */
	u_int		tail;		/* written back to adapter */
};

/*
 * TBRQ (Transmit Buffer Return Queue) entry and queue
 */
struct hetbrq {
	u_int		size;		/* number of entries */
	u_int		thresh;		/* interrupt threshold */
	struct dmamem	mem;		/* memory */
	struct he_tbrqen *tbrq;
	u_int		head;		/* adapter end */
};

/*==================================================================*/

/*
 * TPDs are 32 byte and must be aligned on 64 byte boundaries. That means,
 * that half of the space is free. We use this space to plug in a link for
 * the list of free TPDs. Note, that the m_act member of the mbufs contain
 * a pointer to the dmamap.
 *
 * The maximum number of TDPs is the size of the common transmit packet
 * descriptor ready queue plus the sizes of the transmit buffer return queues
 * (currently only queue 0). We allocate and map these TPD when initializing
 * the card. We also allocate on DMA map for each TPD. Only the map in the
 * last TPD of a packets is used when a packet is transmitted.
 * This is signalled by having the mbuf member of this TPD non-zero and
 * pointing to the mbuf.
 */
#define HE_TPD_SIZE		64
struct tpd {
	struct he_tpd		tpd;	/* at beginning */
	SLIST_ENTRY(tpd)	link;	/* free cid list link */
	struct mbuf		*mbuf;	/* the buf chain */
	bus_dmamap_t		map;	/* map */
	uint32_t		cid;	/* CID */
	uint16_t		no;	/* number of this tpd */
};
SLIST_HEAD(tpd_list, tpd);

#define TPD_SET_USED(SC, I) do {				\
	(SC)->tpd_used[(I) / 8] |= (1 << ((I) % 8));		\
    } while (0)

#define TPD_CLR_USED(SC, I) do {				\
	(SC)->tpd_used[(I) / 8] &= ~(1 << ((I) % 8));		\
    } while (0)

#define TPD_TST_USED(SC, I) ((SC)->tpd_used[(I) / 8] & (1 << ((I) % 8)))

#define TPD_ADDR(SC, I) ((struct tpd *)((char *)sc->tpds.base +	\
    (I) * HE_TPD_SIZE))

/*==================================================================*/

/*
 * External MBUFs. The card needs a lot of mbufs in the pools for high
 * performance. The problem with using mbufs directly is that we would need
 * a dmamap for each of the mbufs. This can exhaust iommu space on the sparc
 * and it eats also a lot of processing time. So we use external mbufs
 * for the small buffers and clusters for the large buffers.
 * For receive group 0 we use 5 ATM cells, for group 1 one (52 byte) ATM
 * cell. The mbuf storage is allocated pagewise and one dmamap is used per
 * page.
 *
 * The handle we give to the card for the small buffers is a word combined
 * of the page number and the number of the chunk in the page. This restricts
 * the number of chunks per page to 256 (8 bit) and the number of pages to
 * 65536 (16 bits).
 *
 * A chunk may be in one of three states: free, on the card and floating around
 * in the system. If it is free, it is on one of the two free lists and
 * start with a struct mbufx_free. Each page has a bitmap that tracks where
 * its chunks are.
 *
 * For large buffers we use mbuf clusters. Here we have two problems: we need
 * to track the buffers on the card (in the case we want to stop it) and
 * we need to map the 64bit mbuf address to a 26bit handle for 64-bit machines.
 * The card uses the buffers in the order we give it to the card. Therefor
 * we can use a private array holding pointers to the mbufs as a circular
 * queue for both tasks. This is done with the lbufs member of softc. The
 * handle for these buffer is the lbufs index ored with a flag.
 */

/* data space in each external mbuf */
#define MBUF0_SIZE	(5 * 48)	/* 240 */
#define MBUF1_SIZE	(52)		/* 1 raw cell */

/* size of the buffer. Must fit data, offset and header */
#define MBUF0_CHUNK	256		/* 16 free bytes */
#define MBUF1_CHUNK	96		/* 44 free bytes */

/* start of actual data in buffer */
#define MBUF0_OFFSET	0
#define MBUF1_OFFSET	16

#define MBUFL_OFFSET	16		/* two pointers for HARP */

#if PAGE_SIZE > 8192
#define	MBUF_ALLOC_SIZE	(8192)
#else
#define	MBUF_ALLOC_SIZE	(PAGE_SIZE)
#endif

/* each allocated page has one of these structures at its very end. */
struct mbuf_page_hdr {
	uint16_t	nchunks;	/* chunks on this page */
	bus_dmamap_t	map;		/* the DMA MAP */
	uint32_t	phys;		/* physical base address */
	uint32_t	hdroff;		/* chunk header offset */
	uint32_t	chunksize;	/* chunk size */
	u_int		pool;		/* pool number */
};
struct mbuf_page {
	char	storage[MBUF_ALLOC_SIZE - sizeof(struct mbuf_page_hdr)];
	struct mbuf_page_hdr	hdr;
};

/* numbers per page */
#define MBUF0_PER_PAGE	((MBUF_ALLOC_SIZE - sizeof(struct mbuf_page_hdr)) / \
    MBUF0_CHUNK)
#define MBUF1_PER_PAGE	((MBUF_ALLOC_SIZE - sizeof(struct mbuf_page_hdr)) / \
    MBUF1_CHUNK)

/*
 * Convert to/from handles
 */
/* small buffers */
#define MBUF_MAKE_HANDLE(PAGENO, CHUNKNO) \
	((((PAGENO) << 10) | (CHUNKNO)) << HE_REGS_RBRQ_ADDR)
#define	MBUF_MAKE_LHANDLE(INDEX) \
	(MBUF_LARGE_FLAG | ((INDEX) << HE_REGS_RBRQ_ADDR))

/* large buffers */
#define MBUF_PARSE_HANDLE(HANDLE, PAGENO, CHUNKNO) do {			\
	(CHUNKNO) = ((HANDLE) >> HE_REGS_RBRQ_ADDR) & 0x3ff;		\
	(PAGENO) = (((HANDLE) >> 10) >> HE_REGS_RBRQ_ADDR) & 0x3fff;	\
    } while (0)
#define	MBUF_PARSE_LHANDLE(HANDLE, INDEX) do {				\
	(INDEX) = ((HANDLE) >> HE_REGS_RBRQ_ADDR) & 0xffffff;		\
    } while (0)

#define MBUF_LARGE_FLAG	0x80000000

/* chunks have the following structure at the end (8 byte) */
struct mbuf_chunk_hdr {
	uint16_t	pageno;
	uint8_t		chunkno;
	uint8_t		flags;
	u_int		ref_cnt;
};
#define	MBUF_CARD	0x01	/* buffer is on card */
#define	MBUF_USED	0x02	/* buffer is somewhere in the system */

#define MBUFX_STORAGE_SIZE(X) (MBUF##X##_CHUNK	\
    - sizeof(struct mbuf_chunk_hdr))

struct mbuf0_chunk {
	char			storage[MBUFX_STORAGE_SIZE(0)];
	struct mbuf_chunk_hdr	hdr;
};

struct mbuf1_chunk {
	char			storage[MBUFX_STORAGE_SIZE(1)];
	struct mbuf_chunk_hdr	hdr;
};

struct mbufx_free {
	struct mbufx_free	*link;
};

/*==================================================================*/

/*
 * Interrupt queue
 */
struct heirq {
	u_int		size;	/* number of entries */
	u_int		thresh;	/* re-interrupt threshold */
	u_int		line;	/* interrupt line to use */
	struct dmamem	mem;	/* interrupt queues */
	uint32_t *	irq;	/* interrupt queue */
	uint32_t 	head;	/* head index */
	uint32_t *	tailp;	/* pointer to tail */
	struct hatm_softc *sc;	/* back pointer */
	u_int		group;	/* interrupt group */
};

/*
 * This structure describes all information for a VCC open on the card.
 * The array of these structures is indexed by the compressed connection ID
 * (CID). This structure must begin with the atmio_vcc.
 */
struct hevcc {
	struct atmio_vcc param;		/* traffic parameters */
	void *		rxhand;		/* NATM protocol block */
	u_int		vflags;		/* private flags */
	uint32_t	ipackets;
	uint32_t	opackets;
	uint32_t	ibytes;
	uint32_t	obytes;

	u_int		rc;		/* rate control group for CBR */
	struct mbuf *	chain;		/* partial received PDU */
	struct mbuf *	last;		/* last mbuf in chain */
	u_int		ntpds;		/* number of active TPDs */
};
#define HE_VCC_OPEN		0x000f0000
#define HE_VCC_RX_OPEN		0x00010000
#define HE_VCC_RX_CLOSING	0x00020000
#define HE_VCC_TX_OPEN		0x00040000
#define HE_VCC_TX_CLOSING	0x00080000
#define HE_VCC_FLOW_CTRL	0x00100000

/*
 * CBR rate groups
 */
struct herg {
	u_int	refcnt;		/* how many connections reference this group */
	u_int	rate;		/* the value */
};

/*
 * Softc
 */
struct hatm_softc {
	struct ifnet		*ifp;
	struct mtx		mtx;		/* lock */
	struct ifmedia		media;		/* media */
	device_t		dev;		/* device */
	int			memid;		/* resoure id for memory */
	struct resource *	memres;		/* memory resource */
	bus_space_handle_t	memh;		/* handle */
	bus_space_tag_t		memt;		/* ... and tag */
	bus_dma_tag_t		parent_tag;	/* global restriction */
	struct cv		vcc_cv;		/* condition variable */
	int			irqid;		/* resource id */
	struct resource *	irqres;		/* resource */
	void *			ih;		/* interrupt handle */
	struct utopia		utopia;		/* utopia state */

	/* rest has to be reset by stop */
	int			he622;		/* this is a HE622 */
	int			pci64;		/* 64bit bus */
	char			prod_id[HE_EEPROM_PROD_ID_LEN + 1];
	char			rev[HE_EEPROM_REV_LEN + 1];
	struct heirq		irq_0;		/* interrupt queues 0 */

	/* generic network controller state */
	u_int			cells_per_row;
	u_int			bytes_per_row;
	u_int			r0_numrows;
	u_int			tx_numrows;
	u_int			r1_numrows;
	u_int			r0_startrow;
	u_int			tx_startrow;
	u_int			r1_startrow;
	u_int			cells_per_lbuf;
	u_int			r0_numbuffs;
	u_int			r1_numbuffs;
	u_int			tx_numbuffs;

	/* HSP */
	struct he_hsp		*hsp;
	struct dmamem		hsp_mem;

	/*** TX ***/
	struct hetbrq		tbrq;		/* TBRQ 0 */
	struct hetpdrq		tpdrq;		/* TPDRQ */
	struct tpd_list		tpd_free;	/* Free TPDs */
	u_int			tpd_nfree;	/* number of free TPDs */
	u_int			tpd_total;	/* total TPDs */
	uint8_t			*tpd_used;	/* bitmap of used TPDs */
	struct dmamem		tpds;		/* TPD memory */
	bus_dma_tag_t		tx_tag;		/* DMA tag for all tx mbufs */

	/*** RX ***/
	/* receive/transmit groups */
	struct herbp		rbp_s0;		/* RBPS0 */
	struct herbp		rbp_l0;		/* RBPL0 */
	struct herbp		rbp_s1;		/* RBPS1 */
	struct herbrq		rbrq_0;		/* RBRQ0 */
	struct herbrq		rbrq_1;		/* RBRQ1 */

	/* list of external mbuf storage */
	bus_dma_tag_t		mbuf_tag;
	struct mbuf_page	**mbuf_pages;
	u_int			mbuf_npages;
	u_int			mbuf_max_pages;
	struct mbufx_free	*mbuf_list[2];

	/* mbuf cluster tracking and mapping for group 0 */
	struct mbuf		**lbufs;	/* mbufs */
	bus_dmamap_t		*rmaps;		/* DMA maps */
	u_int			lbufs_size;
	u_int			lbufs_next;

	/* VCCs */
	struct hevcc		*vccs[HE_MAX_VCCS];
	u_int			cbr_bw;		/* BW allocated to CBR */
	u_int			max_tpd;	/* per VCC */
	u_int			open_vccs;
	uma_zone_t		vcc_zone;

	/* rate groups */
	struct herg		rate_ctrl[HE_REGN_CS_STPER];

	/* memory offsets */
	u_int			tsrb, tsrc, tsrd;
	u_int			rsrb;

	struct cv		cv_rcclose;	/* condition variable */
	uint32_t		rate_grid[16][16]; /* our copy */

	/* sysctl support */
	struct sysctl_ctx_list	sysctl_ctx;
	struct sysctl_oid	*sysctl_tree;

	/* internal statistics */
	struct istats		istats;

	u_int			mpsafe;

#ifdef HATM_DEBUG
	/* debugging */
	u_int			debug;

	/* transmit mbuf count */
	int			txmbuf;
#endif
};

#define READ4(SC,OFF)	bus_space_read_4(SC->memt, SC->memh, (OFF))
#define READ2(SC,OFF)	bus_space_read_2(SC->memt, SC->memh, (OFF))
#define READ1(SC,OFF)	bus_space_read_1(SC->memt, SC->memh, (OFF))

#define WRITE4(SC,OFF,VAL) bus_space_write_4(SC->memt, SC->memh, (OFF), (VAL))
#define WRITE2(SC,OFF,VAL) bus_space_write_2(SC->memt, SC->memh, (OFF), (VAL))
#define WRITE1(SC,OFF,VAL) bus_space_write_1(SC->memt, SC->memh, (OFF), (VAL))

#define BARRIER_R(SC) bus_space_barrier(SC->memt, SC->memh, 0, HE_REGO_END, \
	BUS_SPACE_BARRIER_READ)
#define BARRIER_W(SC) bus_space_barrier(SC->memt, SC->memh, 0, HE_REGO_END, \
	BUS_SPACE_BARRIER_WRITE)
#define BARRIER_RW(SC) bus_space_barrier(SC->memt, SC->memh, 0, HE_REGO_END, \
	BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE)

#define READ_SUNI(SC,OFF) READ4(SC, HE_REGO_SUNI + 4 * (OFF))
#define WRITE_SUNI(SC,OFF,VAL) WRITE4(SC, HE_REGO_SUNI + 4 * (OFF), (VAL))

#define READ_LB4(SC,OFF)						\
    ({									\
	WRITE4(SC, HE_REGO_LB_MEM_ADDR, (OFF));				\
	WRITE4(SC, HE_REGO_LB_MEM_ACCESS,				\
	    (HE_REGM_LB_MEM_HNDSHK | HE_REGM_LB_MEM_READ));		\
	while((READ4(SC, HE_REGO_LB_MEM_ACCESS) & HE_REGM_LB_MEM_HNDSHK))\
		;							\
	READ4(SC, HE_REGO_LB_MEM_DATA);					\
    })
#define WRITE_LB4(SC,OFF,VAL)						\
    do {								\
	WRITE4(SC, HE_REGO_LB_MEM_ADDR, (OFF));				\
	WRITE4(SC, HE_REGO_LB_MEM_DATA, (VAL));				\
	WRITE4(SC, HE_REGO_LB_MEM_ACCESS,				\
	    (HE_REGM_LB_MEM_HNDSHK | HE_REGM_LB_MEM_WRITE));		\
	while((READ4(SC, HE_REGO_LB_MEM_ACCESS) & HE_REGM_LB_MEM_HNDSHK))\
		;							\
    } while(0)

#define WRITE_MEM4(SC,OFF,VAL,SPACE)					\
    do {								\
	WRITE4(SC, HE_REGO_CON_DAT, (VAL));				\
	WRITE4(SC, HE_REGO_CON_CTL,					\
	    (SPACE | HE_REGM_CON_WE | HE_REGM_CON_STATUS | (OFF)));	\
	while((READ4(SC, HE_REGO_CON_CTL) & HE_REGM_CON_STATUS) != 0)	\
		;							\
    } while(0)

#define READ_MEM4(SC,OFF,SPACE)					\
    ({									\
	WRITE4(SC, HE_REGO_CON_CTL,					\
	    (SPACE | HE_REGM_CON_STATUS | (OFF)));			\
	while((READ4(SC, HE_REGO_CON_CTL) & HE_REGM_CON_STATUS) != 0)	\
		;							\
	READ4(SC, HE_REGO_CON_DAT);					\
    })

#define WRITE_TCM4(SC,OFF,VAL) WRITE_MEM4(SC,(OFF),(VAL),HE_REGM_CON_TCM)
#define WRITE_RCM4(SC,OFF,VAL) WRITE_MEM4(SC,(OFF),(VAL),HE_REGM_CON_RCM)
#define WRITE_MBOX4(SC,OFF,VAL) WRITE_MEM4(SC,(OFF),(VAL),HE_REGM_CON_MBOX)

#define READ_TCM4(SC,OFF) READ_MEM4(SC,(OFF),HE_REGM_CON_TCM)
#define READ_RCM4(SC,OFF) READ_MEM4(SC,(OFF),HE_REGM_CON_RCM)
#define READ_MBOX4(SC,OFF) READ_MEM4(SC,(OFF),HE_REGM_CON_MBOX)

#define WRITE_TCM(SC,OFF,BYTES,VAL) 					\
	WRITE_MEM4(SC,(OFF) | ((~(BYTES) & 0xf) << HE_REGS_CON_DIS),	\
	    (VAL), HE_REGM_CON_TCM)
#define WRITE_RCM(SC,OFF,BYTES,VAL) 					\
	WRITE_MEM4(SC,(OFF) | ((~(BYTES) & 0xf) << HE_REGS_CON_DIS),	\
	    (VAL), HE_REGM_CON_RCM)

#define READ_TSR(SC,CID,NR)						\
    ({									\
	uint32_t _v;							\
	if((NR) <= 7) {							\
		_v = READ_TCM4(SC, HE_REGO_TSRA(0,CID,NR));		\
	} else if((NR) <= 11) {						\
		_v = READ_TCM4(SC, HE_REGO_TSRB((SC)->tsrb,CID,(NR-8)));\
	} else if((NR) <= 13) {						\
		_v = READ_TCM4(SC, HE_REGO_TSRC((SC)->tsrc,CID,(NR-12)));\
	} else {							\
		_v = READ_TCM4(SC, HE_REGO_TSRD((SC)->tsrd,CID));	\
	}								\
	_v;								\
    })

#define WRITE_TSR(SC,CID,NR,BEN,VAL)					\
    do {								\
	if((NR) <= 7) {							\
		WRITE_TCM(SC, HE_REGO_TSRA(0,CID,NR),BEN,VAL);		\
	} else if((NR) <= 11) {						\
		WRITE_TCM(SC, HE_REGO_TSRB((SC)->tsrb,CID,(NR-8)),BEN,VAL);\
	} else if((NR) <= 13) {						\
		WRITE_TCM(SC, HE_REGO_TSRC((SC)->tsrc,CID,(NR-12)),BEN,VAL);\
	} else {							\
		WRITE_TCM(SC, HE_REGO_TSRD((SC)->tsrd,CID),BEN,VAL);	\
	}								\
    } while(0)

#define READ_RSR(SC,CID,NR)						\
    ({									\
	uint32_t _v;							\
	if((NR) <= 7) {							\
		_v = READ_RCM4(SC, HE_REGO_RSRA(0,CID,NR));		\
	} else {							\
		_v = READ_RCM4(SC, HE_REGO_RSRB((SC)->rsrb,CID,(NR-8)));\
	}								\
	_v;								\
    })

#define WRITE_RSR(SC,CID,NR,BEN,VAL)					\
    do {								\
	if((NR) <= 7) {							\
		WRITE_RCM(SC, HE_REGO_RSRA(0,CID,NR),BEN,VAL);		\
	} else {							\
		WRITE_RCM(SC, HE_REGO_RSRB((SC)->rsrb,CID,(NR-8)),BEN,VAL);\
	}								\
    } while(0)

#ifdef HATM_DEBUG
#define DBG(SC, FL, PRINT) do {						\
	if((SC)->debug & DBG_##FL) { 					\
		if_printf((SC)->ifp, "%s: ", __func__);			\
		printf PRINT;						\
		printf("\n");						\
	}								\
    } while (0)

enum {
	DBG_DUMMY	= 0x0001,	/* default value for -DHATM_DEBUG */
	DBG_RX		= 0x0002,
	DBG_TX		= 0x0004,
	DBG_VCC		= 0x0008,
	DBG_IOCTL	= 0x0010,
	DBG_ATTACH	= 0x0020,
	DBG_INTR	= 0x0040,
	DBG_DMA		= 0x0080,
	DBG_DMAH	= 0x0100,
	DBG_DUMP	= 0x0200,

	DBG_ALL		= 0x03ff
};

#else
#define DBG(SC, FL, PRINT)
#endif

u_int hatm_cps2atmf(uint32_t);
u_int hatm_atmf2cps(uint32_t);

void hatm_intr(void *);
int hatm_ioctl(struct ifnet *, u_long, caddr_t);
void hatm_initialize(struct hatm_softc *);
void hatm_stop(struct hatm_softc *sc);
void hatm_start(struct ifnet *);

void hatm_rx(struct hatm_softc *sc, u_int cid, u_int flags, struct mbuf *m,
    u_int len);
void hatm_tx_complete(struct hatm_softc *sc, struct tpd *tpd, uint32_t);

int hatm_tx_vcc_can_open(struct hatm_softc *sc, u_int cid, struct hevcc *);
void hatm_tx_vcc_open(struct hatm_softc *sc, u_int cid);
void hatm_rx_vcc_open(struct hatm_softc *sc, u_int cid);
void hatm_tx_vcc_close(struct hatm_softc *sc, u_int cid);
void hatm_rx_vcc_close(struct hatm_softc *sc, u_int cid);
void hatm_tx_vcc_closed(struct hatm_softc *sc, u_int cid);
void hatm_vcc_closed(struct hatm_softc *sc, u_int cid);
void hatm_load_vc(struct hatm_softc *sc, u_int cid, int reopen);

void hatm_ext_free(struct mbufx_free **, struct mbufx_free *);
OpenPOWER on IntegriCloud