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
|
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _SYS_DMFE_IMPL_H
#define _SYS_DMFE_IMPL_H
#include <sys/types.h>
#include <sys/stream.h>
#include <sys/strsun.h>
#include <sys/stat.h>
#include <sys/pci.h>
#include <sys/note.h>
#include <sys/modctl.h>
#include <sys/kstat.h>
#include <sys/ethernet.h>
#include <sys/devops.h>
#include <sys/debug.h>
#include <sys/conf.h>
#include <sys/vlan.h>
#include <sys/dditypes.h>
#include <sys/ddi.h>
#include <sys/sunddi.h>
#include <sys/mii.h>
#include <sys/mac_provider.h>
#include <sys/mac_ether.h>
#include "dmfe.h"
#define DMFE_MAX_PKT_SIZE (VLAN_TAGSZ + ETHERMAX + ETHERFCSL)
#define DRIVER_NAME "dmfe"
/*
* Describes the identity of a specific chip
*/
typedef struct {
uint16_t vendor;
uint16_t device;
uint8_t revision;
uint8_t spare;
} chip_id_t;
/*
* Describes the state of a descriptor ring
*
* NOTE: n_free and next_busy are only used for the Tx descriptors
* and are not valid on the receive side.
*/
typedef struct {
uint32_t n_desc; /* # of descriptors */
uint32_t n_free; /* # of free descriptors */
uint32_t next_free; /* next index to use/check */
uint32_t next_busy; /* next index to reclaim */
} desc_state_t;
/*
* Describes one chunk of allocated DMA-able memory
*/
typedef struct {
ddi_dma_handle_t dma_hdl;
ddi_acc_handle_t acc_hdl;
size_t alength; /* allocated size */
caddr_t mem_va; /* CPU VA of memory */
uint32_t spare1;
uint32_t mem_dvma; /* DVMA addr of memory */
caddr_t setup_va;
uint32_t spare2;
uint32_t setup_dvma;
int spare3;
int ncookies;
} dma_area_t;
/*
* Indexes into the driver-specific kstats, divided into:
*
* cyclic activity
* reasons for waking the factotum
* the factotum's activities
*/
enum {
KS_CYCLIC_RUN,
KS_INTERRUPT,
KS_TX_STALL,
KS_CHIP_ERROR,
KS_FACTOTUM_RUN,
KS_RECOVERY,
KS_DRV_COUNT
};
/*
* Actual state of the DM9102A chip
*/
enum chip_state {
CHIP_ERROR = -1, /* error, need reset */
CHIP_UNKNOWN, /* Initial state only */
CHIP_RESET, /* reset, need init */
CHIP_STOPPED, /* Tx/Rx stopped */
CHIP_TX_ONLY, /* Tx (re)started */
CHIP_TX_RX, /* Tx & Rx (re)started */
CHIP_RUNNING /* with interrupts */
};
/*
* Required state according to MAC
*/
enum mac_state {
DMFE_MAC_UNKNOWN,
DMFE_MAC_RESET,
DMFE_MAC_STOPPED,
DMFE_MAC_STARTED
};
/*
* (Internal) return values from ioctl subroutines
*/
enum ioc_reply {
IOC_INVAL = -1, /* bad, NAK with EINVAL */
IOC_DONE, /* OK, reply sent */
IOC_REPLY, /* OK, just send reply */
IOC_ACK, /* OK, just send ACK */
IOC_RESTART, /* OK, restart & reply */
IOC_RESTART_ACK /* OK, restart & ACK */
};
/*
* Per-instance soft-state structure
*/
typedef struct dmfe {
/*
* These fields are set by attach() and unchanged thereafter ...
*/
dev_info_t *devinfo; /* device instance */
mac_handle_t mh; /* MAC instance data */
mii_handle_t mii; /* MII handle */
ddi_acc_handle_t io_handle; /* DDI I/O handle */
caddr_t io_reg; /* mapped registers */
boolean_t suspended;
uint32_t debug; /* per-instance debug */
uint32_t progress; /* attach tracking */
chip_id_t chipid;
uint8_t vendor_addr[ETHERADDRL];
char ifname[12]; /* "dmfeXXXX" */
dma_area_t tx_desc; /* transmit descriptors */
dma_area_t tx_buff; /* transmit buffers */
dma_area_t rx_desc; /* receive descriptors */
dma_area_t rx_buff; /* receive buffers */
ddi_periodic_t cycid; /* periodical callback */
ddi_softintr_t factotum_id; /* identity of factotum */
ddi_iblock_cookie_t iblk;
/*
* Locks:
*
* <milock> is used only by the MII (PHY) level code, to ensure
* exclusive access during the bit-twiddling needed to send
* signals along the MII serial bus. These operations are
* --S--L--O--W-- so we keep this lock separate, so that
* faster operations (e.g. interrupts) aren't delayed by
* waiting for it.
*
* <oplock> is a general "outer" lock, protecting most r/w data
* and chip state. It is also acquired by the interrupt
* handler.
*
* <rxlock> is used to protect the Rx-side buffers, descriptors,
* and statistics during a single call to dmfe_getp().
* This is called from inside the interrupt handler, but
* <oplock> is not held across this call.
*
* <txlock> is an "inner" lock, and protects only the Tx-side
* data below and in the ring buffers/descriptors. The
* Tx-side code uses only this lock, avoiding contention
* with the receive-side code.
*
* Any of the locks can be acquired singly, but where multiple
* locks are acquired, they *must* be in the order:
*
* milock >>> oplock >>> rxlock >>> txlock.
*
* *None* of these locks may be held across calls out to the
* MAC routines mac_rx() or mac_tx_notify(); MAC locks must
* be regarded as *outermost* locks in all cases, as they will
* already be held before calling the ioctl() or get_stats()
* entry points - which then have to acquire multiple locks, in
* the order described here.
*/
kmutex_t milock[1];
kmutex_t oplock[1];
kmutex_t rxlock[1];
kmutex_t txlock[1];
/*
* DMFE Extended kstats, protected by <oplock>
*/
kstat_t *ksp_drv;
kstat_named_t *knp_drv;
/*
* GLD statistics; the prefix tells which lock each is protected by.
*/
uint64_t rx_stats_ipackets;
uint64_t rx_stats_multi;
uint64_t rx_stats_bcast;
uint64_t rx_stats_ierrors;
uint64_t rx_stats_norcvbuf;
uint64_t rx_stats_rbytes;
uint64_t rx_stats_missed;
uint64_t rx_stats_align;
uint64_t rx_stats_fcs;
uint64_t rx_stats_toolong;
uint64_t rx_stats_macrcv_errors;
uint64_t rx_stats_overflow;
uint64_t rx_stats_short;
uint64_t tx_stats_oerrors;
uint64_t tx_stats_opackets;
uint64_t tx_stats_multi;
uint64_t tx_stats_bcast;
uint64_t tx_stats_obytes;
uint64_t tx_stats_collisions;
uint64_t tx_stats_nocarrier;
uint64_t tx_stats_xmtlatecoll;
uint64_t tx_stats_excoll;
uint64_t tx_stats_macxmt_errors;
uint64_t tx_stats_jabber;
uint64_t tx_stats_defer;
uint64_t tx_stats_first_coll;
uint64_t tx_stats_multi_coll;
uint64_t tx_stats_underflow;
/*
* These two sets of desciptors are manipulated during
* packet receive/transmit respectively.
*/
desc_state_t rx; /* describes Rx ring */
desc_state_t tx; /* describes Tx ring */
/*
* Miscellaneous Tx-side variables (protected by txlock)
*/
uint32_t tx_pending_tix; /* tix since reclaim */
uint8_t *tx_mcast; /* bitmask: pkt is mcast */
uint8_t *tx_bcast; /* bitmask: pkt is bcast */
/*
* Miscellaneous operating variables (protected by oplock)
*/
uint16_t factotum_flag; /* callback pending */
uint16_t need_setup; /* send-setup pending */
uint32_t opmode; /* operating mode shadow */
uint32_t imask; /* interrupt mask shadow */
enum mac_state mac_state; /* RESET/STOPPED/STARTED */
enum chip_state chip_state; /* see above */
/*
* Current Ethernet address & multicast map ...
*/
uint8_t curr_addr[ETHERADDRL];
uint8_t mcast_refs[MCASTBUF_SIZE];
boolean_t addr_set;
/*
* Guard element used to check data integrity
*/
uint64_t dmfe_guard;
} dmfe_t;
/*
* 'Progress' bit flags ...
*/
#define PROGRESS_CONFIG 0x0001 /* config space initialised */
#define PROGRESS_MUTEX 0x0002 /* mutexes initialized */
#define PROGRESS_REGS 0x0004 /* registers mapped */
#define PROGRESS_BUFS 0x0008 /* buffers allocated */
#define PROGRESS_SOFTINT 0x0010 /* softint registered */
#define PROGRESS_HWINT 0x0020 /* h/w interrupt registered */
/*
* Sync a DMA area described by a dma_area_t
*/
#define DMA_SYNC(descp, flag) ((void) ddi_dma_sync((descp)->dma_hdl, \
0, (descp)->alength, flag))
/*
* Next value of a cyclic index
*/
#define NEXT(index, limit) ((index)+1 < (limit) ? (index)+1 : 0);
/*
* Copy an ethernet address
*/
#define ethaddr_copy(src, dst) bcopy((src), (dst), ETHERADDRL)
/*
* Get/set/increment a (64-bit) driver-private kstat
*/
#define DRV_KS_GET(dmfep, id) \
(((dmfep)->knp_drv) ? ((dmfep)->knp_drv)[id].value.ui64 : 0)
#define DRV_KS_SET(dmfep, id, val) \
do { \
if ((dmfep)->knp_drv) \
((dmfep)->knp_drv)[id].value.ui64 = (val); \
_NOTE(CONSTANTCONDITION) \
} while (0)
#define DRV_KS_INC(dmfep, id) \
do { \
if ((dmfep)->knp_drv) \
((dmfep)->knp_drv)[id].value.ui64 += 1; \
_NOTE(CONSTANTCONDITION) \
} while (0)
#define DMFE_GUARD 0x1919603003090218
/*
* Inter-source-file linkage ...
*/
/* dmfe_log.c */
void dmfe_warning(dmfe_t *dmfep, const char *fmt, ...);
void dmfe_error(dmfe_t *dmfep, const char *fmt, ...);
void dmfe_notice(dmfe_t *dmfep, const char *fmt, ...);
void dmfe_log(dmfe_t *dmfep, const char *fmt, ...);
void dmfe_log_init(void);
void dmfe_log_fini(void);
/* dmfe_main.c */
uint32_t dmfe_chip_get32(dmfe_t *dmfep, off_t offset);
void dmfe_chip_put32(dmfe_t *dmfep, off_t offset, uint32_t value);
/* dmfe_mii.c */
void dmfe_read_eeprom(dmfe_t *dmfep, uint16_t addr, uint8_t *ptr, int cnt);
boolean_t dmfe_init_phy(dmfe_t *dmfep);
#endif /* _SYS_DMFE_IMPL_H */
|