1dd52495fSSaurabh Misra /*
2dd52495fSSaurabh Misra * CDDL HEADER START
3dd52495fSSaurabh Misra *
4dd52495fSSaurabh Misra * The contents of this file are subject to the terms of the
5dd52495fSSaurabh Misra * Common Development and Distribution License (the "License").
6dd52495fSSaurabh Misra * You may not use this file except in compliance with the License.
7dd52495fSSaurabh Misra *
8dd52495fSSaurabh Misra * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9dd52495fSSaurabh Misra * or http://www.opensolaris.org/os/licensing.
10dd52495fSSaurabh Misra * See the License for the specific language governing permissions
11dd52495fSSaurabh Misra * and limitations under the License.
12dd52495fSSaurabh Misra *
13dd52495fSSaurabh Misra * When distributing Covered Code, include this CDDL HEADER in each
14dd52495fSSaurabh Misra * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15dd52495fSSaurabh Misra * If applicable, add the following below this CDDL HEADER, with the
16dd52495fSSaurabh Misra * fields enclosed by brackets "[]" replaced with your own identifying
17dd52495fSSaurabh Misra * information: Portions Copyright [yyyy] [name of copyright owner]
18dd52495fSSaurabh Misra *
19dd52495fSSaurabh Misra * CDDL HEADER END
20dd52495fSSaurabh Misra */
21dd52495fSSaurabh Misra
22dd52495fSSaurabh Misra /*
237a0c1e29SCrisson Guanghao Hu * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
24dd52495fSSaurabh Misra */
25dd52495fSSaurabh Misra #include <sys/stream.h>
26dd52495fSSaurabh Misra #include <sys/strsun.h>
27dd52495fSSaurabh Misra #include <sys/stat.h>
28dd52495fSSaurabh Misra #include <sys/pci.h>
29dd52495fSSaurabh Misra #include <sys/modctl.h>
30dd52495fSSaurabh Misra #include <sys/kstat.h>
31dd52495fSSaurabh Misra #include <sys/ethernet.h>
32dd52495fSSaurabh Misra #include <sys/devops.h>
33dd52495fSSaurabh Misra #include <sys/debug.h>
34dd52495fSSaurabh Misra #include <sys/conf.h>
35dd52495fSSaurabh Misra #include <sys/sysmacros.h>
36dd52495fSSaurabh Misra #include <sys/dditypes.h>
37dd52495fSSaurabh Misra #include <sys/ddi.h>
38dd52495fSSaurabh Misra #include <sys/sunddi.h>
39dd52495fSSaurabh Misra #include <sys/miiregs.h>
40dd52495fSSaurabh Misra #include <sys/byteorder.h>
41dd52495fSSaurabh Misra #include <sys/cyclic.h>
42dd52495fSSaurabh Misra #include <sys/note.h>
43dd52495fSSaurabh Misra #include <sys/crc32.h>
44dd52495fSSaurabh Misra #include <sys/mac_provider.h>
45dd52495fSSaurabh Misra #include <sys/mac_ether.h>
46dd52495fSSaurabh Misra #include <sys/vlan.h>
47dd52495fSSaurabh Misra #include <sys/errno.h>
48dd52495fSSaurabh Misra #include <sys/sdt.h>
49dd52495fSSaurabh Misra #include <sys/strsubr.h>
50dd52495fSSaurabh Misra
51dd52495fSSaurabh Misra #include "bfe.h"
52dd52495fSSaurabh Misra #include "bfe_hw.h"
53dd52495fSSaurabh Misra
54dd52495fSSaurabh Misra
55dd52495fSSaurabh Misra /*
56dd52495fSSaurabh Misra * Broadcom BCM4401 chipsets use two rings :
57dd52495fSSaurabh Misra *
58dd52495fSSaurabh Misra * - One TX : For sending packets down the wire.
59dd52495fSSaurabh Misra * - One RX : For receving packets.
60dd52495fSSaurabh Misra *
61dd52495fSSaurabh Misra * Each ring can have any number of descriptors (configured during attach).
62dd52495fSSaurabh Misra * As of now we configure only 128 descriptor per ring (TX/RX). Each descriptor
63dd52495fSSaurabh Misra * has address (desc_addr) and control (desc_ctl) which holds a DMA buffer for
64dd52495fSSaurabh Misra * the packet and control information (like start/end of frame or end of table).
65dd52495fSSaurabh Misra * The descriptor table is allocated first and then a DMA buffer (for a packet)
66dd52495fSSaurabh Misra * is allocated and linked to each descriptor.
67dd52495fSSaurabh Misra *
68dd52495fSSaurabh Misra * Each descriptor entry is bfe_desc_t structure in bfe. During TX/RX
69dd52495fSSaurabh Misra * interrupt, the stat register will point to current descriptor being
70dd52495fSSaurabh Misra * processed.
71dd52495fSSaurabh Misra *
72dd52495fSSaurabh Misra * Here's an example of TX and RX ring :
73dd52495fSSaurabh Misra *
74dd52495fSSaurabh Misra * TX:
75dd52495fSSaurabh Misra *
76dd52495fSSaurabh Misra * Base of the descriptor table is programmed using BFE_DMATX_CTRL control
77dd52495fSSaurabh Misra * register. Each 'addr' points to DMA buffer (or packet data buffer) to
78dd52495fSSaurabh Misra * be transmitted and 'ctl' has the length of the packet (usually MTU).
79dd52495fSSaurabh Misra *
80dd52495fSSaurabh Misra * ----------------------|
81dd52495fSSaurabh Misra * | addr |Descriptor 0 |
82dd52495fSSaurabh Misra * | ctl | |
83dd52495fSSaurabh Misra * ----------------------|
84dd52495fSSaurabh Misra * | addr |Descriptor 1 | SOF (start of the frame)
85dd52495fSSaurabh Misra * | ctl | |
86dd52495fSSaurabh Misra * ----------------------|
87dd52495fSSaurabh Misra * | ... |Descriptor... | EOF (end of the frame)
88dd52495fSSaurabh Misra * | ... | |
89dd52495fSSaurabh Misra * ----------------------|
90dd52495fSSaurabh Misra * | addr |Descritor 127 |
91dd52495fSSaurabh Misra * | ctl | EOT | EOT (End of Table)
92dd52495fSSaurabh Misra * ----------------------|
93dd52495fSSaurabh Misra *
94dd52495fSSaurabh Misra * 'r_curr_desc' : pointer to current descriptor which can be used to transmit
95dd52495fSSaurabh Misra * a packet.
96dd52495fSSaurabh Misra * 'r_avail_desc' : decremented whenever a packet is being sent.
97dd52495fSSaurabh Misra * 'r_cons_desc' : incremented whenever a packet is sent down the wire and
98dd52495fSSaurabh Misra * notified by an interrupt to bfe driver.
99dd52495fSSaurabh Misra *
100dd52495fSSaurabh Misra * RX:
101dd52495fSSaurabh Misra *
102dd52495fSSaurabh Misra * Base of the descriptor table is programmed using BFE_DMARX_CTRL control
103dd52495fSSaurabh Misra * register. Each 'addr' points to DMA buffer (or packet data buffer). 'ctl'
104dd52495fSSaurabh Misra * contains the size of the DMA buffer and all the DMA buffers are
105dd52495fSSaurabh Misra * pre-allocated during attach and hence the maxmium size of the packet is
106dd52495fSSaurabh Misra * also known (r_buf_len from the bfe_rint_t structure). During RX interrupt
107dd52495fSSaurabh Misra * the packet length is embedded in bfe_header_t which is added by the
108dd52495fSSaurabh Misra * chip in the beginning of the packet.
109dd52495fSSaurabh Misra *
110dd52495fSSaurabh Misra * ----------------------|
111dd52495fSSaurabh Misra * | addr |Descriptor 0 |
112dd52495fSSaurabh Misra * | ctl | |
113dd52495fSSaurabh Misra * ----------------------|
114dd52495fSSaurabh Misra * | addr |Descriptor 1 |
115dd52495fSSaurabh Misra * | ctl | |
116dd52495fSSaurabh Misra * ----------------------|
117dd52495fSSaurabh Misra * | ... |Descriptor... |
118dd52495fSSaurabh Misra * | ... | |
119dd52495fSSaurabh Misra * ----------------------|
120dd52495fSSaurabh Misra * | addr |Descriptor 127|
121dd52495fSSaurabh Misra * | ctl | EOT | EOT (End of Table)
122dd52495fSSaurabh Misra * ----------------------|
123dd52495fSSaurabh Misra *
124dd52495fSSaurabh Misra * 'r_curr_desc' : pointer to current descriptor while receving a packet.
125dd52495fSSaurabh Misra *
126dd52495fSSaurabh Misra */
127dd52495fSSaurabh Misra
128dd52495fSSaurabh Misra #define MODULE_NAME "bfe"
129dd52495fSSaurabh Misra
130dd52495fSSaurabh Misra /*
131dd52495fSSaurabh Misra * Used for checking PHY (link state, speed)
132dd52495fSSaurabh Misra */
133dd52495fSSaurabh Misra #define BFE_TIMEOUT_INTERVAL (1000 * 1000 * 1000)
134dd52495fSSaurabh Misra
135dd52495fSSaurabh Misra
136dd52495fSSaurabh Misra /*
137dd52495fSSaurabh Misra * Chip restart action and reason for restart
138dd52495fSSaurabh Misra */
139dd52495fSSaurabh Misra #define BFE_ACTION_RESTART 0x1 /* For restarting the chip */
140dd52495fSSaurabh Misra #define BFE_ACTION_RESTART_SETPROP 0x2 /* restart due to setprop */
141dd52495fSSaurabh Misra #define BFE_ACTION_RESTART_FAULT 0x4 /* restart due to fault */
142dd52495fSSaurabh Misra #define BFE_ACTION_RESTART_PKT 0x8 /* restart due to pkt timeout */
143dd52495fSSaurabh Misra
144dd52495fSSaurabh Misra static char bfe_ident[] = "bfe driver for Broadcom BCM4401 chipsets";
145dd52495fSSaurabh Misra
146dd52495fSSaurabh Misra /*
147dd52495fSSaurabh Misra * Function Prototypes for bfe driver.
148dd52495fSSaurabh Misra */
149dd52495fSSaurabh Misra static int bfe_check_link(bfe_t *);
150dd52495fSSaurabh Misra static void bfe_report_link(bfe_t *);
151dd52495fSSaurabh Misra static void bfe_chip_halt(bfe_t *);
152dd52495fSSaurabh Misra static void bfe_chip_reset(bfe_t *);
153dd52495fSSaurabh Misra static void bfe_tx_desc_init(bfe_ring_t *);
154dd52495fSSaurabh Misra static void bfe_rx_desc_init(bfe_ring_t *);
155dd52495fSSaurabh Misra static void bfe_set_rx_mode(bfe_t *);
156dd52495fSSaurabh Misra static void bfe_enable_chip_intrs(bfe_t *);
157dd52495fSSaurabh Misra static void bfe_chip_restart(bfe_t *);
158dd52495fSSaurabh Misra static void bfe_init_vars(bfe_t *);
159dd52495fSSaurabh Misra static void bfe_clear_stats(bfe_t *);
160dd52495fSSaurabh Misra static void bfe_gather_stats(bfe_t *);
161dd52495fSSaurabh Misra static void bfe_error(dev_info_t *, char *, ...);
162dd52495fSSaurabh Misra static int bfe_mac_getprop(void *, const char *, mac_prop_id_t, uint_t,
1630dc2366fSVenugopal Iyer void *);
164dd52495fSSaurabh Misra static int bfe_mac_setprop(void *, const char *, mac_prop_id_t, uint_t,
165dd52495fSSaurabh Misra const void *);
166dd52495fSSaurabh Misra static int bfe_tx_reclaim(bfe_ring_t *);
167dd52495fSSaurabh Misra int bfe_mac_set_ether_addr(void *, const uint8_t *);
168dd52495fSSaurabh Misra
169dd52495fSSaurabh Misra
170dd52495fSSaurabh Misra /*
171dd52495fSSaurabh Misra * Macros for ddi_dma_sync().
172dd52495fSSaurabh Misra */
173dd52495fSSaurabh Misra #define SYNC_DESC(r, s, l, d) \
174dd52495fSSaurabh Misra (void) ddi_dma_sync(r->r_desc_dma_handle, \
175dd52495fSSaurabh Misra (off_t)(s * sizeof (bfe_desc_t)), \
176dd52495fSSaurabh Misra (size_t)(l * sizeof (bfe_desc_t)), \
177dd52495fSSaurabh Misra d)
178dd52495fSSaurabh Misra
179dd52495fSSaurabh Misra #define SYNC_BUF(r, s, b, l, d) \
180dd52495fSSaurabh Misra (void) ddi_dma_sync(r->r_buf_dma[s].handle, \
181dd52495fSSaurabh Misra (off_t)(b), (size_t)(l), d)
182dd52495fSSaurabh Misra
183dd52495fSSaurabh Misra /*
184dd52495fSSaurabh Misra * Supported Broadcom BCM4401 Cards.
185dd52495fSSaurabh Misra */
186dd52495fSSaurabh Misra static bfe_cards_t bfe_cards[] = {
187dd52495fSSaurabh Misra { 0x14e4, 0x170c, "BCM4401 100Base-TX"},
188dd52495fSSaurabh Misra };
189dd52495fSSaurabh Misra
190dd52495fSSaurabh Misra
191dd52495fSSaurabh Misra /*
192dd52495fSSaurabh Misra * DMA attributes for device registers, packet data (buffer) and
193dd52495fSSaurabh Misra * descriptor table.
194dd52495fSSaurabh Misra */
195dd52495fSSaurabh Misra static struct ddi_device_acc_attr bfe_dev_attr = {
196dd52495fSSaurabh Misra DDI_DEVICE_ATTR_V0,
197dd52495fSSaurabh Misra DDI_STRUCTURE_LE_ACC,
198dd52495fSSaurabh Misra DDI_STRICTORDER_ACC
199dd52495fSSaurabh Misra };
200dd52495fSSaurabh Misra
201dd52495fSSaurabh Misra static struct ddi_device_acc_attr bfe_buf_attr = {
202dd52495fSSaurabh Misra DDI_DEVICE_ATTR_V0,
203dd52495fSSaurabh Misra DDI_NEVERSWAP_ACC, /* native endianness */
204dd52495fSSaurabh Misra DDI_STRICTORDER_ACC
205dd52495fSSaurabh Misra };
206dd52495fSSaurabh Misra
207dd52495fSSaurabh Misra static ddi_dma_attr_t bfe_dma_attr_buf = {
208dd52495fSSaurabh Misra DMA_ATTR_V0, /* dma_attr_version */
209dd52495fSSaurabh Misra 0, /* dma_attr_addr_lo */
210dd52495fSSaurabh Misra BFE_PCI_DMA - 1, /* dma_attr_addr_hi */
211dd52495fSSaurabh Misra 0x1fff, /* dma_attr_count_max */
212dd52495fSSaurabh Misra 8, /* dma_attr_align */
213dd52495fSSaurabh Misra 0, /* dma_attr_burstsizes */
214dd52495fSSaurabh Misra 1, /* dma_attr_minxfer */
215dd52495fSSaurabh Misra 0x1fff, /* dma_attr_maxxfer */
216dd52495fSSaurabh Misra BFE_PCI_DMA - 1, /* dma_attr_seg */
217dd52495fSSaurabh Misra 1, /* dma_attr_sgllen */
218dd52495fSSaurabh Misra 1, /* dma_attr_granular */
219dd52495fSSaurabh Misra 0 /* dma_attr_flags */
220dd52495fSSaurabh Misra };
221dd52495fSSaurabh Misra
222dd52495fSSaurabh Misra static ddi_dma_attr_t bfe_dma_attr_desc = {
223dd52495fSSaurabh Misra DMA_ATTR_V0, /* dma_attr_version */
224dd52495fSSaurabh Misra 0, /* dma_attr_addr_lo */
225dd52495fSSaurabh Misra BFE_PCI_DMA - 1, /* dma_attr_addr_hi */
226dd52495fSSaurabh Misra BFE_PCI_DMA - 1, /* dma_attr_count_max */
227dd52495fSSaurabh Misra BFE_DESC_ALIGN, /* dma_attr_align */
228dd52495fSSaurabh Misra 0, /* dma_attr_burstsizes */
229dd52495fSSaurabh Misra 1, /* dma_attr_minxfer */
230dd52495fSSaurabh Misra BFE_PCI_DMA - 1, /* dma_attr_maxxfer */
231dd52495fSSaurabh Misra BFE_PCI_DMA - 1, /* dma_attr_seg */
232dd52495fSSaurabh Misra 1, /* dma_attr_sgllen */
233dd52495fSSaurabh Misra 1, /* dma_attr_granular */
234dd52495fSSaurabh Misra 0 /* dma_attr_flags */
235dd52495fSSaurabh Misra };
236dd52495fSSaurabh Misra
237dd52495fSSaurabh Misra /*
238dd52495fSSaurabh Misra * Ethernet broadcast addresses.
239dd52495fSSaurabh Misra */
240dd52495fSSaurabh Misra static uchar_t bfe_broadcast[ETHERADDRL] = {
241dd52495fSSaurabh Misra 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
242dd52495fSSaurabh Misra };
243dd52495fSSaurabh Misra
244dd52495fSSaurabh Misra #define ASSERT_ALL_LOCKS(bfe) { \
245dd52495fSSaurabh Misra ASSERT(mutex_owned(&bfe->bfe_tx_ring.r_lock)); \
246dd52495fSSaurabh Misra ASSERT(rw_write_held(&bfe->bfe_rwlock)); \
247dd52495fSSaurabh Misra }
248dd52495fSSaurabh Misra
249dd52495fSSaurabh Misra /*
250dd52495fSSaurabh Misra * Debugging and error reproting code.
251dd52495fSSaurabh Misra */
252dd52495fSSaurabh Misra static void
bfe_error(dev_info_t * dip,char * fmt,...)253dd52495fSSaurabh Misra bfe_error(dev_info_t *dip, char *fmt, ...)
254dd52495fSSaurabh Misra {
255dd52495fSSaurabh Misra va_list ap;
256dd52495fSSaurabh Misra char buf[256];
257dd52495fSSaurabh Misra
258dd52495fSSaurabh Misra va_start(ap, fmt);
259dd52495fSSaurabh Misra (void) vsnprintf(buf, sizeof (buf), fmt, ap);
260dd52495fSSaurabh Misra va_end(ap);
261dd52495fSSaurabh Misra
262dd52495fSSaurabh Misra if (dip) {
263dd52495fSSaurabh Misra cmn_err(CE_WARN, "%s%d: %s",
264dd52495fSSaurabh Misra ddi_driver_name(dip), ddi_get_instance(dip), buf);
265dd52495fSSaurabh Misra } else {
266dd52495fSSaurabh Misra cmn_err(CE_WARN, "bfe: %s", buf);
267dd52495fSSaurabh Misra }
268dd52495fSSaurabh Misra }
269dd52495fSSaurabh Misra
270dd52495fSSaurabh Misra /*
271dd52495fSSaurabh Misra * Grabs all necessary locks to block any other operation on the chip.
272dd52495fSSaurabh Misra */
273dd52495fSSaurabh Misra static void
bfe_grab_locks(bfe_t * bfe)274dd52495fSSaurabh Misra bfe_grab_locks(bfe_t *bfe)
275dd52495fSSaurabh Misra {
276dd52495fSSaurabh Misra bfe_ring_t *tx = &bfe->bfe_tx_ring;
277dd52495fSSaurabh Misra
278dd52495fSSaurabh Misra /*
279dd52495fSSaurabh Misra * Grab all the locks.
280dd52495fSSaurabh Misra * - bfe_rwlock : locks down whole chip including RX.
281dd52495fSSaurabh Misra * - tx's r_lock : locks down only TX side.
282dd52495fSSaurabh Misra */
283dd52495fSSaurabh Misra rw_enter(&bfe->bfe_rwlock, RW_WRITER);
284dd52495fSSaurabh Misra mutex_enter(&tx->r_lock);
285dd52495fSSaurabh Misra
286dd52495fSSaurabh Misra /*
287dd52495fSSaurabh Misra * Note that we don't use RX's r_lock.
288dd52495fSSaurabh Misra */
289dd52495fSSaurabh Misra }
290dd52495fSSaurabh Misra
291dd52495fSSaurabh Misra /*
292dd52495fSSaurabh Misra * Release lock on chip/drver.
293dd52495fSSaurabh Misra */
294dd52495fSSaurabh Misra static void
bfe_release_locks(bfe_t * bfe)295dd52495fSSaurabh Misra bfe_release_locks(bfe_t *bfe)
296dd52495fSSaurabh Misra {
297dd52495fSSaurabh Misra bfe_ring_t *tx = &bfe->bfe_tx_ring;
298dd52495fSSaurabh Misra
299dd52495fSSaurabh Misra /*
300dd52495fSSaurabh Misra * Release all the locks in the order in which they were grabbed.
301dd52495fSSaurabh Misra */
302dd52495fSSaurabh Misra mutex_exit(&tx->r_lock);
303dd52495fSSaurabh Misra rw_exit(&bfe->bfe_rwlock);
304dd52495fSSaurabh Misra }
305dd52495fSSaurabh Misra
306dd52495fSSaurabh Misra
307dd52495fSSaurabh Misra /*
308dd52495fSSaurabh Misra * It's used to make sure that the write to device register was successful.
309dd52495fSSaurabh Misra */
310dd52495fSSaurabh Misra static int
bfe_wait_bit(bfe_t * bfe,uint32_t reg,uint32_t bit,ulong_t t,const int clear)311dd52495fSSaurabh Misra bfe_wait_bit(bfe_t *bfe, uint32_t reg, uint32_t bit,
312dd52495fSSaurabh Misra ulong_t t, const int clear)
313dd52495fSSaurabh Misra {
314dd52495fSSaurabh Misra ulong_t i;
315dd52495fSSaurabh Misra uint32_t v;
316dd52495fSSaurabh Misra
317dd52495fSSaurabh Misra for (i = 0; i < t; i++) {
318dd52495fSSaurabh Misra v = INL(bfe, reg);
319dd52495fSSaurabh Misra
320dd52495fSSaurabh Misra if (clear && !(v & bit))
321dd52495fSSaurabh Misra break;
322dd52495fSSaurabh Misra
323dd52495fSSaurabh Misra if (!clear && (v & bit))
324dd52495fSSaurabh Misra break;
325dd52495fSSaurabh Misra
326dd52495fSSaurabh Misra drv_usecwait(10);
327dd52495fSSaurabh Misra }
328dd52495fSSaurabh Misra
329dd52495fSSaurabh Misra /* if device still didn't see the value */
330dd52495fSSaurabh Misra if (i == t)
331dd52495fSSaurabh Misra return (-1);
332dd52495fSSaurabh Misra
333dd52495fSSaurabh Misra return (0);
334dd52495fSSaurabh Misra }
335dd52495fSSaurabh Misra
336dd52495fSSaurabh Misra /*
337dd52495fSSaurabh Misra * PHY functions (read, write, stop, reset and startup)
338dd52495fSSaurabh Misra */
339dd52495fSSaurabh Misra static int
bfe_read_phy(bfe_t * bfe,uint32_t reg)340dd52495fSSaurabh Misra bfe_read_phy(bfe_t *bfe, uint32_t reg)
341dd52495fSSaurabh Misra {
342dd52495fSSaurabh Misra OUTL(bfe, BFE_EMAC_ISTAT, BFE_EMAC_INT_MII);
343dd52495fSSaurabh Misra OUTL(bfe, BFE_MDIO_DATA, (BFE_MDIO_SB_START |
344dd52495fSSaurabh Misra (BFE_MDIO_OP_READ << BFE_MDIO_OP_SHIFT) |
345dd52495fSSaurabh Misra (bfe->bfe_phy_addr << BFE_MDIO_PMD_SHIFT) |
346dd52495fSSaurabh Misra (reg << BFE_MDIO_RA_SHIFT) |
347dd52495fSSaurabh Misra (BFE_MDIO_TA_VALID << BFE_MDIO_TA_SHIFT)));
348dd52495fSSaurabh Misra
349dd52495fSSaurabh Misra (void) bfe_wait_bit(bfe, BFE_EMAC_ISTAT, BFE_EMAC_INT_MII, 10, 0);
350dd52495fSSaurabh Misra
351dd52495fSSaurabh Misra return ((INL(bfe, BFE_MDIO_DATA) & BFE_MDIO_DATA_DATA));
352dd52495fSSaurabh Misra }
353dd52495fSSaurabh Misra
354dd52495fSSaurabh Misra static void
bfe_write_phy(bfe_t * bfe,uint32_t reg,uint32_t val)355dd52495fSSaurabh Misra bfe_write_phy(bfe_t *bfe, uint32_t reg, uint32_t val)
356dd52495fSSaurabh Misra {
357dd52495fSSaurabh Misra OUTL(bfe, BFE_EMAC_ISTAT, BFE_EMAC_INT_MII);
358dd52495fSSaurabh Misra OUTL(bfe, BFE_MDIO_DATA, (BFE_MDIO_SB_START |
359dd52495fSSaurabh Misra (BFE_MDIO_OP_WRITE << BFE_MDIO_OP_SHIFT) |
360dd52495fSSaurabh Misra (bfe->bfe_phy_addr << BFE_MDIO_PMD_SHIFT) |
361dd52495fSSaurabh Misra (reg << BFE_MDIO_RA_SHIFT) |
362dd52495fSSaurabh Misra (BFE_MDIO_TA_VALID << BFE_MDIO_TA_SHIFT) |
363dd52495fSSaurabh Misra (val & BFE_MDIO_DATA_DATA)));
364dd52495fSSaurabh Misra
365dd52495fSSaurabh Misra (void) bfe_wait_bit(bfe, BFE_EMAC_ISTAT, BFE_EMAC_INT_MII, 10, 0);
366dd52495fSSaurabh Misra }
367dd52495fSSaurabh Misra
368dd52495fSSaurabh Misra /*
369dd52495fSSaurabh Misra * It resets the PHY layer.
370dd52495fSSaurabh Misra */
371dd52495fSSaurabh Misra static int
bfe_reset_phy(bfe_t * bfe)372dd52495fSSaurabh Misra bfe_reset_phy(bfe_t *bfe)
373dd52495fSSaurabh Misra {
374dd52495fSSaurabh Misra uint32_t i;
375dd52495fSSaurabh Misra
376dd52495fSSaurabh Misra bfe_write_phy(bfe, MII_CONTROL, MII_CONTROL_RESET);
377dd52495fSSaurabh Misra drv_usecwait(100);
378dd52495fSSaurabh Misra for (i = 0; i < 10; i++) {
379dd52495fSSaurabh Misra if (bfe_read_phy(bfe, MII_CONTROL) &
380dd52495fSSaurabh Misra MII_CONTROL_RESET) {
381dd52495fSSaurabh Misra drv_usecwait(500);
382dd52495fSSaurabh Misra continue;
383dd52495fSSaurabh Misra }
384dd52495fSSaurabh Misra
385dd52495fSSaurabh Misra break;
386dd52495fSSaurabh Misra }
387dd52495fSSaurabh Misra
388dd52495fSSaurabh Misra if (i == 10) {
389dd52495fSSaurabh Misra bfe_error(bfe->bfe_dip, "Timeout waiting for PHY to reset");
390dd52495fSSaurabh Misra bfe->bfe_phy_state = BFE_PHY_RESET_TIMEOUT;
391dd52495fSSaurabh Misra return (BFE_FAILURE);
392dd52495fSSaurabh Misra }
393dd52495fSSaurabh Misra
394dd52495fSSaurabh Misra bfe->bfe_phy_state = BFE_PHY_RESET_DONE;
395dd52495fSSaurabh Misra
396dd52495fSSaurabh Misra return (BFE_SUCCESS);
397dd52495fSSaurabh Misra }
398dd52495fSSaurabh Misra
399dd52495fSSaurabh Misra /*
400dd52495fSSaurabh Misra * Make sure timer function is out of our way and especially during
401dd52495fSSaurabh Misra * detach.
402dd52495fSSaurabh Misra */
403dd52495fSSaurabh Misra static void
bfe_stop_timer(bfe_t * bfe)404dd52495fSSaurabh Misra bfe_stop_timer(bfe_t *bfe)
405dd52495fSSaurabh Misra {
406dd52495fSSaurabh Misra if (bfe->bfe_periodic_id) {
407dd52495fSSaurabh Misra ddi_periodic_delete(bfe->bfe_periodic_id);
408dd52495fSSaurabh Misra bfe->bfe_periodic_id = NULL;
409dd52495fSSaurabh Misra }
410dd52495fSSaurabh Misra }
411dd52495fSSaurabh Misra
412dd52495fSSaurabh Misra /*
413dd52495fSSaurabh Misra * Stops the PHY
414dd52495fSSaurabh Misra */
415dd52495fSSaurabh Misra static void
bfe_stop_phy(bfe_t * bfe)416dd52495fSSaurabh Misra bfe_stop_phy(bfe_t *bfe)
417dd52495fSSaurabh Misra {
418dd52495fSSaurabh Misra bfe_write_phy(bfe, MII_CONTROL, MII_CONTROL_PWRDN |
419dd52495fSSaurabh Misra MII_CONTROL_ISOLATE);
420dd52495fSSaurabh Misra
421dd52495fSSaurabh Misra bfe->bfe_chip.link = LINK_STATE_UNKNOWN;
422dd52495fSSaurabh Misra bfe->bfe_chip.speed = 0;
423dd52495fSSaurabh Misra bfe->bfe_chip.duplex = LINK_DUPLEX_UNKNOWN;
424dd52495fSSaurabh Misra
425dd52495fSSaurabh Misra bfe->bfe_phy_state = BFE_PHY_STOPPED;
426dd52495fSSaurabh Misra
427dd52495fSSaurabh Misra /*
428dd52495fSSaurabh Misra * Report the link status to MAC layer.
429dd52495fSSaurabh Misra */
430dd52495fSSaurabh Misra if (bfe->bfe_machdl != NULL)
431dd52495fSSaurabh Misra (void) bfe_report_link(bfe);
432dd52495fSSaurabh Misra }
433dd52495fSSaurabh Misra
434dd52495fSSaurabh Misra static int
bfe_probe_phy(bfe_t * bfe)435dd52495fSSaurabh Misra bfe_probe_phy(bfe_t *bfe)
436dd52495fSSaurabh Misra {
437dd52495fSSaurabh Misra int phy;
438dd52495fSSaurabh Misra uint32_t status;
439dd52495fSSaurabh Misra
440dd52495fSSaurabh Misra if (bfe->bfe_phy_addr) {
441dd52495fSSaurabh Misra status = bfe_read_phy(bfe, MII_STATUS);
442dd52495fSSaurabh Misra if (status != 0xffff && status != 0) {
443dd52495fSSaurabh Misra bfe_write_phy(bfe, MII_CONTROL, 0);
444dd52495fSSaurabh Misra return (BFE_SUCCESS);
445dd52495fSSaurabh Misra }
446dd52495fSSaurabh Misra }
447dd52495fSSaurabh Misra
448dd52495fSSaurabh Misra for (phy = 0; phy < 32; phy++) {
449dd52495fSSaurabh Misra bfe->bfe_phy_addr = phy;
450dd52495fSSaurabh Misra status = bfe_read_phy(bfe, MII_STATUS);
451dd52495fSSaurabh Misra if (status != 0xffff && status != 0) {
452dd52495fSSaurabh Misra bfe_write_phy(bfe, MII_CONTROL, 0);
453dd52495fSSaurabh Misra return (BFE_SUCCESS);
454dd52495fSSaurabh Misra }
455dd52495fSSaurabh Misra }
456dd52495fSSaurabh Misra
457dd52495fSSaurabh Misra return (BFE_FAILURE);
458dd52495fSSaurabh Misra }
459dd52495fSSaurabh Misra
460dd52495fSSaurabh Misra /*
461dd52495fSSaurabh Misra * This timeout function fires at BFE_TIMEOUT_INTERVAL to check the link
462dd52495fSSaurabh Misra * status.
463dd52495fSSaurabh Misra */
464dd52495fSSaurabh Misra static void
bfe_timeout(void * arg)465dd52495fSSaurabh Misra bfe_timeout(void *arg)
466dd52495fSSaurabh Misra {
467dd52495fSSaurabh Misra bfe_t *bfe = (bfe_t *)arg;
468954c6b5eSSaurabh Misra int resched = 0;
469dd52495fSSaurabh Misra
470dd52495fSSaurabh Misra /*
471dd52495fSSaurabh Misra * We don't grab any lock because bfe can't go away.
472dd52495fSSaurabh Misra * untimeout() will wait for this timeout instance to complete.
473dd52495fSSaurabh Misra */
474dd52495fSSaurabh Misra if (bfe->bfe_chip_action & BFE_ACTION_RESTART) {
475dd52495fSSaurabh Misra /*
476dd52495fSSaurabh Misra * Restart the chip.
477dd52495fSSaurabh Misra */
478dd52495fSSaurabh Misra bfe_grab_locks(bfe);
479dd52495fSSaurabh Misra bfe_chip_restart(bfe);
480dd52495fSSaurabh Misra bfe->bfe_chip_action &= ~BFE_ACTION_RESTART;
481dd52495fSSaurabh Misra bfe->bfe_chip_action &= ~BFE_ACTION_RESTART_FAULT;
482dd52495fSSaurabh Misra bfe->bfe_chip_action &= ~BFE_ACTION_RESTART_PKT;
483dd52495fSSaurabh Misra bfe_release_locks(bfe);
484dd52495fSSaurabh Misra mac_tx_update(bfe->bfe_machdl);
485dd52495fSSaurabh Misra /* Restart will register a new timeout */
486dd52495fSSaurabh Misra return;
487dd52495fSSaurabh Misra }
488dd52495fSSaurabh Misra
489dd52495fSSaurabh Misra rw_enter(&bfe->bfe_rwlock, RW_READER);
490dd52495fSSaurabh Misra
491dd52495fSSaurabh Misra if (bfe->bfe_chip_state == BFE_CHIP_ACTIVE) {
492dd52495fSSaurabh Misra hrtime_t hr;
493dd52495fSSaurabh Misra
494dd52495fSSaurabh Misra hr = gethrtime();
495dd52495fSSaurabh Misra if (bfe->bfe_tx_stall_time != 0 &&
496dd52495fSSaurabh Misra hr > bfe->bfe_tx_stall_time) {
497dd52495fSSaurabh Misra DTRACE_PROBE2(chip__restart, int, bfe->bfe_unit,
498dd52495fSSaurabh Misra char *, "pkt timeout");
499dd52495fSSaurabh Misra bfe->bfe_chip_action |=
500dd52495fSSaurabh Misra (BFE_ACTION_RESTART | BFE_ACTION_RESTART_PKT);
501dd52495fSSaurabh Misra bfe->bfe_tx_stall_time = 0;
502dd52495fSSaurabh Misra }
503dd52495fSSaurabh Misra }
504dd52495fSSaurabh Misra
505dd52495fSSaurabh Misra if (bfe->bfe_phy_state == BFE_PHY_STARTED) {
506dd52495fSSaurabh Misra /*
507dd52495fSSaurabh Misra * Report the link status to MAC layer if link status changed.
508dd52495fSSaurabh Misra */
509dd52495fSSaurabh Misra if (bfe_check_link(bfe)) {
510dd52495fSSaurabh Misra bfe_report_link(bfe);
511dd52495fSSaurabh Misra if (bfe->bfe_chip.link == LINK_STATE_UP) {
512dd52495fSSaurabh Misra uint32_t val, flow;
513dd52495fSSaurabh Misra
514dd52495fSSaurabh Misra val = INL(bfe, BFE_TX_CTRL);
515dd52495fSSaurabh Misra val &= ~BFE_TX_DUPLEX;
516dd52495fSSaurabh Misra if (bfe->bfe_chip.duplex == LINK_DUPLEX_FULL) {
517dd52495fSSaurabh Misra val |= BFE_TX_DUPLEX;
518dd52495fSSaurabh Misra flow = INL(bfe, BFE_RXCONF);
519dd52495fSSaurabh Misra flow &= ~BFE_RXCONF_FLOW;
520dd52495fSSaurabh Misra OUTL(bfe, BFE_RXCONF, flow);
521dd52495fSSaurabh Misra
522dd52495fSSaurabh Misra flow = INL(bfe, BFE_MAC_FLOW);
523dd52495fSSaurabh Misra flow &= ~(BFE_FLOW_RX_HIWAT);
524dd52495fSSaurabh Misra OUTL(bfe, BFE_MAC_FLOW, flow);
525dd52495fSSaurabh Misra }
526dd52495fSSaurabh Misra
527954c6b5eSSaurabh Misra resched = 1;
528954c6b5eSSaurabh Misra
529dd52495fSSaurabh Misra OUTL(bfe, BFE_TX_CTRL, val);
530dd52495fSSaurabh Misra DTRACE_PROBE1(link__up,
531dd52495fSSaurabh Misra int, bfe->bfe_unit);
532dd52495fSSaurabh Misra }
533dd52495fSSaurabh Misra }
534dd52495fSSaurabh Misra }
535dd52495fSSaurabh Misra
536dd52495fSSaurabh Misra rw_exit(&bfe->bfe_rwlock);
537954c6b5eSSaurabh Misra
538954c6b5eSSaurabh Misra if (resched)
539954c6b5eSSaurabh Misra mac_tx_update(bfe->bfe_machdl);
540dd52495fSSaurabh Misra }
541dd52495fSSaurabh Misra
542dd52495fSSaurabh Misra /*
543dd52495fSSaurabh Misra * Starts PHY layer.
544dd52495fSSaurabh Misra */
545dd52495fSSaurabh Misra static int
bfe_startup_phy(bfe_t * bfe)546dd52495fSSaurabh Misra bfe_startup_phy(bfe_t *bfe)
547dd52495fSSaurabh Misra {
548dd52495fSSaurabh Misra uint16_t bmsr, bmcr, anar;
549dd52495fSSaurabh Misra int prog, s;
550dd52495fSSaurabh Misra int phyid1, phyid2;
551dd52495fSSaurabh Misra
552dd52495fSSaurabh Misra if (bfe_probe_phy(bfe) == BFE_FAILURE) {
553dd52495fSSaurabh Misra bfe->bfe_phy_state = BFE_PHY_NOTFOUND;
554dd52495fSSaurabh Misra return (BFE_FAILURE);
555dd52495fSSaurabh Misra }
556dd52495fSSaurabh Misra
557dd52495fSSaurabh Misra (void) bfe_reset_phy(bfe);
558dd52495fSSaurabh Misra
559dd52495fSSaurabh Misra phyid1 = bfe_read_phy(bfe, MII_PHYIDH);
560dd52495fSSaurabh Misra phyid2 = bfe_read_phy(bfe, MII_PHYIDL);
561dd52495fSSaurabh Misra bfe->bfe_phy_id = (phyid1 << 16) | phyid2;
562dd52495fSSaurabh Misra
563dd52495fSSaurabh Misra bmsr = bfe_read_phy(bfe, MII_STATUS);
564dd52495fSSaurabh Misra anar = bfe_read_phy(bfe, MII_AN_ADVERT);
565dd52495fSSaurabh Misra
566dd52495fSSaurabh Misra again:
567dd52495fSSaurabh Misra anar &= ~(MII_ABILITY_100BASE_T4 |
568dd52495fSSaurabh Misra MII_ABILITY_100BASE_TX_FD | MII_ABILITY_100BASE_TX |
569dd52495fSSaurabh Misra MII_ABILITY_10BASE_T_FD | MII_ABILITY_10BASE_T);
570dd52495fSSaurabh Misra
571dd52495fSSaurabh Misra /*
572dd52495fSSaurabh Misra * Supported hardware modes are in bmsr.
573dd52495fSSaurabh Misra */
574dd52495fSSaurabh Misra bfe->bfe_chip.bmsr = bmsr;
575dd52495fSSaurabh Misra
576dd52495fSSaurabh Misra /*
577dd52495fSSaurabh Misra * Assume no capabilities are supported in the hardware.
578dd52495fSSaurabh Misra */
579dd52495fSSaurabh Misra bfe->bfe_cap_aneg = bfe->bfe_cap_100T4 =
580dd52495fSSaurabh Misra bfe->bfe_cap_100fdx = bfe->bfe_cap_100hdx =
581dd52495fSSaurabh Misra bfe->bfe_cap_10fdx = bfe->bfe_cap_10hdx = 0;
582dd52495fSSaurabh Misra
583dd52495fSSaurabh Misra /*
584dd52495fSSaurabh Misra * Assume property is set.
585dd52495fSSaurabh Misra */
586dd52495fSSaurabh Misra s = 1;
587dd52495fSSaurabh Misra if (!(bfe->bfe_chip_action & BFE_ACTION_RESTART_SETPROP)) {
588dd52495fSSaurabh Misra /*
589dd52495fSSaurabh Misra * Property is not set which means bfe_mac_setprop()
590dd52495fSSaurabh Misra * is not called on us.
591dd52495fSSaurabh Misra */
592dd52495fSSaurabh Misra s = 0;
593dd52495fSSaurabh Misra }
594dd52495fSSaurabh Misra
595dd52495fSSaurabh Misra bmcr = prog = 0;
596dd52495fSSaurabh Misra
597dd52495fSSaurabh Misra if (bmsr & MII_STATUS_100_BASEX_FD) {
598dd52495fSSaurabh Misra bfe->bfe_cap_100fdx = 1;
599dd52495fSSaurabh Misra if (s == 0) {
600dd52495fSSaurabh Misra anar |= MII_ABILITY_100BASE_TX_FD;
601dd52495fSSaurabh Misra bfe->bfe_adv_100fdx = 1;
602dd52495fSSaurabh Misra prog++;
603dd52495fSSaurabh Misra } else if (bfe->bfe_adv_100fdx) {
604dd52495fSSaurabh Misra anar |= MII_ABILITY_100BASE_TX_FD;
605dd52495fSSaurabh Misra prog++;
606dd52495fSSaurabh Misra }
607dd52495fSSaurabh Misra }
608dd52495fSSaurabh Misra
609dd52495fSSaurabh Misra if (bmsr & MII_STATUS_100_BASE_T4) {
610dd52495fSSaurabh Misra bfe->bfe_cap_100T4 = 1;
611dd52495fSSaurabh Misra if (s == 0) {
612dd52495fSSaurabh Misra anar |= MII_ABILITY_100BASE_T4;
613dd52495fSSaurabh Misra bfe->bfe_adv_100T4 = 1;
614dd52495fSSaurabh Misra prog++;
615dd52495fSSaurabh Misra } else if (bfe->bfe_adv_100T4) {
616dd52495fSSaurabh Misra anar |= MII_ABILITY_100BASE_T4;
617dd52495fSSaurabh Misra prog++;
618dd52495fSSaurabh Misra }
619dd52495fSSaurabh Misra }
620dd52495fSSaurabh Misra
621dd52495fSSaurabh Misra if (bmsr & MII_STATUS_100_BASEX) {
622dd52495fSSaurabh Misra bfe->bfe_cap_100hdx = 1;
623dd52495fSSaurabh Misra if (s == 0) {
624dd52495fSSaurabh Misra anar |= MII_ABILITY_100BASE_TX;
625dd52495fSSaurabh Misra bfe->bfe_adv_100hdx = 1;
626dd52495fSSaurabh Misra prog++;
627dd52495fSSaurabh Misra } else if (bfe->bfe_adv_100hdx) {
628dd52495fSSaurabh Misra anar |= MII_ABILITY_100BASE_TX;
629dd52495fSSaurabh Misra prog++;
630dd52495fSSaurabh Misra }
631dd52495fSSaurabh Misra }
632dd52495fSSaurabh Misra
633dd52495fSSaurabh Misra if (bmsr & MII_STATUS_10_FD) {
634dd52495fSSaurabh Misra bfe->bfe_cap_10fdx = 1;
635dd52495fSSaurabh Misra if (s == 0) {
636dd52495fSSaurabh Misra anar |= MII_ABILITY_10BASE_T_FD;
637dd52495fSSaurabh Misra bfe->bfe_adv_10fdx = 1;
638dd52495fSSaurabh Misra prog++;
639dd52495fSSaurabh Misra } else if (bfe->bfe_adv_10fdx) {
640dd52495fSSaurabh Misra anar |= MII_ABILITY_10BASE_T_FD;
641dd52495fSSaurabh Misra prog++;
642dd52495fSSaurabh Misra }
643dd52495fSSaurabh Misra }
644dd52495fSSaurabh Misra
645dd52495fSSaurabh Misra if (bmsr & MII_STATUS_10) {
646dd52495fSSaurabh Misra bfe->bfe_cap_10hdx = 1;
647dd52495fSSaurabh Misra if (s == 0) {
648dd52495fSSaurabh Misra anar |= MII_ABILITY_10BASE_T;
649dd52495fSSaurabh Misra bfe->bfe_adv_10hdx = 1;
650dd52495fSSaurabh Misra prog++;
651dd52495fSSaurabh Misra } else if (bfe->bfe_adv_10hdx) {
652dd52495fSSaurabh Misra anar |= MII_ABILITY_10BASE_T;
653dd52495fSSaurabh Misra prog++;
654dd52495fSSaurabh Misra }
655dd52495fSSaurabh Misra }
656dd52495fSSaurabh Misra
657dd52495fSSaurabh Misra if (bmsr & MII_STATUS_CANAUTONEG) {
658dd52495fSSaurabh Misra bfe->bfe_cap_aneg = 1;
659dd52495fSSaurabh Misra if (s == 0) {
660dd52495fSSaurabh Misra bfe->bfe_adv_aneg = 1;
661dd52495fSSaurabh Misra }
662dd52495fSSaurabh Misra }
663dd52495fSSaurabh Misra
664dd52495fSSaurabh Misra if (prog == 0) {
665dd52495fSSaurabh Misra if (s == 0) {
666dd52495fSSaurabh Misra bfe_error(bfe->bfe_dip,
667dd52495fSSaurabh Misra "No valid link mode selected. Powering down PHY");
668dd52495fSSaurabh Misra bfe_stop_phy(bfe);
669dd52495fSSaurabh Misra bfe_report_link(bfe);
670dd52495fSSaurabh Misra return (BFE_FAILURE);
671dd52495fSSaurabh Misra }
672dd52495fSSaurabh Misra
673dd52495fSSaurabh Misra /*
674dd52495fSSaurabh Misra * If property is set then user would have goofed up. So we
675dd52495fSSaurabh Misra * go back to default properties.
676dd52495fSSaurabh Misra */
677dd52495fSSaurabh Misra bfe->bfe_chip_action &= ~BFE_ACTION_RESTART_SETPROP;
678dd52495fSSaurabh Misra goto again;
679dd52495fSSaurabh Misra }
680dd52495fSSaurabh Misra
681dd52495fSSaurabh Misra if (bfe->bfe_adv_aneg && (bmsr & MII_STATUS_CANAUTONEG)) {
682dd52495fSSaurabh Misra bmcr = (MII_CONTROL_ANE | MII_CONTROL_RSAN);
683dd52495fSSaurabh Misra } else {
684dd52495fSSaurabh Misra if (bfe->bfe_adv_100fdx)
685dd52495fSSaurabh Misra bmcr = (MII_CONTROL_100MB | MII_CONTROL_FDUPLEX);
686dd52495fSSaurabh Misra else if (bfe->bfe_adv_100hdx)
687dd52495fSSaurabh Misra bmcr = MII_CONTROL_100MB;
688dd52495fSSaurabh Misra else if (bfe->bfe_adv_10fdx)
689dd52495fSSaurabh Misra bmcr = MII_CONTROL_FDUPLEX;
690dd52495fSSaurabh Misra else
691dd52495fSSaurabh Misra bmcr = 0; /* 10HDX */
692dd52495fSSaurabh Misra }
693dd52495fSSaurabh Misra
694dd52495fSSaurabh Misra if (prog)
695dd52495fSSaurabh Misra bfe_write_phy(bfe, MII_AN_ADVERT, anar);
696dd52495fSSaurabh Misra
697dd52495fSSaurabh Misra if (bmcr)
698dd52495fSSaurabh Misra bfe_write_phy(bfe, MII_CONTROL, bmcr);
699dd52495fSSaurabh Misra
700dd52495fSSaurabh Misra bfe->bfe_mii_anar = anar;
701dd52495fSSaurabh Misra bfe->bfe_mii_bmcr = bmcr;
702dd52495fSSaurabh Misra bfe->bfe_phy_state = BFE_PHY_STARTED;
703dd52495fSSaurabh Misra
704dd52495fSSaurabh Misra if (bfe->bfe_periodic_id == NULL) {
705dd52495fSSaurabh Misra bfe->bfe_periodic_id = ddi_periodic_add(bfe_timeout,
706dd52495fSSaurabh Misra (void *)bfe, BFE_TIMEOUT_INTERVAL, DDI_IPL_0);
707dd52495fSSaurabh Misra
708dd52495fSSaurabh Misra DTRACE_PROBE1(first__timeout, int, bfe->bfe_unit);
709dd52495fSSaurabh Misra }
710dd52495fSSaurabh Misra
711dd52495fSSaurabh Misra DTRACE_PROBE4(phy_started, int, bfe->bfe_unit,
712dd52495fSSaurabh Misra int, bmsr, int, bmcr, int, anar);
713dd52495fSSaurabh Misra
714dd52495fSSaurabh Misra return (BFE_SUCCESS);
715dd52495fSSaurabh Misra }
716dd52495fSSaurabh Misra
717dd52495fSSaurabh Misra /*
718dd52495fSSaurabh Misra * Reports link status back to MAC Layer.
719dd52495fSSaurabh Misra */
720dd52495fSSaurabh Misra static void
bfe_report_link(bfe_t * bfe)721dd52495fSSaurabh Misra bfe_report_link(bfe_t *bfe)
722dd52495fSSaurabh Misra {
723dd52495fSSaurabh Misra mac_link_update(bfe->bfe_machdl, bfe->bfe_chip.link);
724dd52495fSSaurabh Misra }
725dd52495fSSaurabh Misra
726dd52495fSSaurabh Misra /*
727dd52495fSSaurabh Misra * Reads PHY/MII registers and get the link status for us.
728dd52495fSSaurabh Misra */
729dd52495fSSaurabh Misra static int
bfe_check_link(bfe_t * bfe)730dd52495fSSaurabh Misra bfe_check_link(bfe_t *bfe)
731dd52495fSSaurabh Misra {
732dd52495fSSaurabh Misra uint16_t bmsr, bmcr, anar, anlpar;
733dd52495fSSaurabh Misra int speed, duplex, link;
734dd52495fSSaurabh Misra
735dd52495fSSaurabh Misra speed = bfe->bfe_chip.speed;
736dd52495fSSaurabh Misra duplex = bfe->bfe_chip.duplex;
737dd52495fSSaurabh Misra link = bfe->bfe_chip.link;
738dd52495fSSaurabh Misra
739dd52495fSSaurabh Misra bmsr = bfe_read_phy(bfe, MII_STATUS);
740dd52495fSSaurabh Misra bfe->bfe_mii_bmsr = bmsr;
741dd52495fSSaurabh Misra
742dd52495fSSaurabh Misra bmcr = bfe_read_phy(bfe, MII_CONTROL);
743dd52495fSSaurabh Misra
744dd52495fSSaurabh Misra anar = bfe_read_phy(bfe, MII_AN_ADVERT);
745dd52495fSSaurabh Misra bfe->bfe_mii_anar = anar;
746dd52495fSSaurabh Misra
747dd52495fSSaurabh Misra anlpar = bfe_read_phy(bfe, MII_AN_LPABLE);
748dd52495fSSaurabh Misra bfe->bfe_mii_anlpar = anlpar;
749dd52495fSSaurabh Misra
750dd52495fSSaurabh Misra bfe->bfe_mii_exp = bfe_read_phy(bfe, MII_AN_EXPANSION);
751dd52495fSSaurabh Misra
752dd52495fSSaurabh Misra /*
753dd52495fSSaurabh Misra * If exp register is not present in PHY.
754dd52495fSSaurabh Misra */
755dd52495fSSaurabh Misra if (bfe->bfe_mii_exp == 0xffff) {
756dd52495fSSaurabh Misra bfe->bfe_mii_exp = 0;
757dd52495fSSaurabh Misra }
758dd52495fSSaurabh Misra
759dd52495fSSaurabh Misra if ((bmsr & MII_STATUS_LINKUP) == 0) {
760dd52495fSSaurabh Misra bfe->bfe_chip.link = LINK_STATE_DOWN;
761dd52495fSSaurabh Misra bfe->bfe_chip.speed = 0;
762dd52495fSSaurabh Misra bfe->bfe_chip.duplex = LINK_DUPLEX_UNKNOWN;
763dd52495fSSaurabh Misra goto done;
764dd52495fSSaurabh Misra }
765dd52495fSSaurabh Misra
766dd52495fSSaurabh Misra bfe->bfe_chip.link = LINK_STATE_UP;
767dd52495fSSaurabh Misra
768dd52495fSSaurabh Misra if (!(bmcr & MII_CONTROL_ANE)) {
769dd52495fSSaurabh Misra /* Forced mode */
770dd52495fSSaurabh Misra if (bmcr & MII_CONTROL_100MB)
771dd52495fSSaurabh Misra bfe->bfe_chip.speed = 100000000;
772dd52495fSSaurabh Misra else
773dd52495fSSaurabh Misra bfe->bfe_chip.speed = 10000000;
774dd52495fSSaurabh Misra
775dd52495fSSaurabh Misra if (bmcr & MII_CONTROL_FDUPLEX)
776dd52495fSSaurabh Misra bfe->bfe_chip.duplex = LINK_DUPLEX_FULL;
777dd52495fSSaurabh Misra else
778dd52495fSSaurabh Misra bfe->bfe_chip.duplex = LINK_DUPLEX_HALF;
779dd52495fSSaurabh Misra
780dd52495fSSaurabh Misra } else if ((!(bmsr & MII_STATUS_CANAUTONEG)) ||
781dd52495fSSaurabh Misra (!(bmsr & MII_STATUS_ANDONE))) {
782dd52495fSSaurabh Misra bfe->bfe_chip.speed = 0;
783dd52495fSSaurabh Misra bfe->bfe_chip.duplex = LINK_DUPLEX_UNKNOWN;
784dd52495fSSaurabh Misra } else if (anar & anlpar & MII_ABILITY_100BASE_TX_FD) {
785dd52495fSSaurabh Misra bfe->bfe_chip.speed = 100000000;
786dd52495fSSaurabh Misra bfe->bfe_chip.duplex = LINK_DUPLEX_FULL;
787dd52495fSSaurabh Misra } else if (anar & anlpar & MII_ABILITY_100BASE_T4) {
788dd52495fSSaurabh Misra bfe->bfe_chip.speed = 100000000;
789dd52495fSSaurabh Misra bfe->bfe_chip.duplex = LINK_DUPLEX_HALF;
790dd52495fSSaurabh Misra } else if (anar & anlpar & MII_ABILITY_100BASE_TX) {
791dd52495fSSaurabh Misra bfe->bfe_chip.speed = 100000000;
792dd52495fSSaurabh Misra bfe->bfe_chip.duplex = LINK_DUPLEX_HALF;
793dd52495fSSaurabh Misra } else if (anar & anlpar & MII_ABILITY_10BASE_T_FD) {
794dd52495fSSaurabh Misra bfe->bfe_chip.speed = 10000000;
795dd52495fSSaurabh Misra bfe->bfe_chip.duplex = LINK_DUPLEX_FULL;
796dd52495fSSaurabh Misra } else if (anar & anlpar & MII_ABILITY_10BASE_T) {
797dd52495fSSaurabh Misra bfe->bfe_chip.speed = 10000000;
798dd52495fSSaurabh Misra bfe->bfe_chip.duplex = LINK_DUPLEX_HALF;
799dd52495fSSaurabh Misra } else {
800dd52495fSSaurabh Misra bfe->bfe_chip.speed = 0;
801dd52495fSSaurabh Misra bfe->bfe_chip.duplex = LINK_DUPLEX_UNKNOWN;
802dd52495fSSaurabh Misra }
803dd52495fSSaurabh Misra
804dd52495fSSaurabh Misra done:
805dd52495fSSaurabh Misra /*
806dd52495fSSaurabh Misra * If speed or link status or duplex mode changed then report to
807dd52495fSSaurabh Misra * MAC layer which is done by the caller.
808dd52495fSSaurabh Misra */
809dd52495fSSaurabh Misra if (speed != bfe->bfe_chip.speed ||
810dd52495fSSaurabh Misra duplex != bfe->bfe_chip.duplex ||
811dd52495fSSaurabh Misra link != bfe->bfe_chip.link) {
812dd52495fSSaurabh Misra return (1);
813dd52495fSSaurabh Misra }
814dd52495fSSaurabh Misra
815dd52495fSSaurabh Misra return (0);
816dd52495fSSaurabh Misra }
817dd52495fSSaurabh Misra
818dd52495fSSaurabh Misra static void
bfe_cam_write(bfe_t * bfe,uchar_t * d,int index)819dd52495fSSaurabh Misra bfe_cam_write(bfe_t *bfe, uchar_t *d, int index)
820dd52495fSSaurabh Misra {
821dd52495fSSaurabh Misra uint32_t v;
822dd52495fSSaurabh Misra
823dd52495fSSaurabh Misra v = ((uint32_t)d[2] << 24);
824dd52495fSSaurabh Misra v |= ((uint32_t)d[3] << 16);
825dd52495fSSaurabh Misra v |= ((uint32_t)d[4] << 8);
826dd52495fSSaurabh Misra v |= (uint32_t)d[5];
827dd52495fSSaurabh Misra
828dd52495fSSaurabh Misra OUTL(bfe, BFE_CAM_DATA_LO, v);
829dd52495fSSaurabh Misra v = (BFE_CAM_HI_VALID |
830dd52495fSSaurabh Misra (((uint32_t)d[0]) << 8) |
831dd52495fSSaurabh Misra (((uint32_t)d[1])));
832dd52495fSSaurabh Misra
833dd52495fSSaurabh Misra OUTL(bfe, BFE_CAM_DATA_HI, v);
834dd52495fSSaurabh Misra OUTL(bfe, BFE_CAM_CTRL, (BFE_CAM_WRITE |
835dd52495fSSaurabh Misra ((uint32_t)index << BFE_CAM_INDEX_SHIFT)));
836dd52495fSSaurabh Misra (void) bfe_wait_bit(bfe, BFE_CAM_CTRL, BFE_CAM_BUSY, 10, 1);
837dd52495fSSaurabh Misra }
838dd52495fSSaurabh Misra
839dd52495fSSaurabh Misra /*
840dd52495fSSaurabh Misra * Chip related functions (halt, reset, start).
841dd52495fSSaurabh Misra */
842dd52495fSSaurabh Misra static void
bfe_chip_halt(bfe_t * bfe)843dd52495fSSaurabh Misra bfe_chip_halt(bfe_t *bfe)
844dd52495fSSaurabh Misra {
845dd52495fSSaurabh Misra /*
846dd52495fSSaurabh Misra * Disables interrupts.
847dd52495fSSaurabh Misra */
848dd52495fSSaurabh Misra OUTL(bfe, BFE_INTR_MASK, 0);
849dd52495fSSaurabh Misra FLUSH(bfe, BFE_INTR_MASK);
850dd52495fSSaurabh Misra
851dd52495fSSaurabh Misra OUTL(bfe, BFE_ENET_CTRL, BFE_ENET_DISABLE);
852dd52495fSSaurabh Misra
853dd52495fSSaurabh Misra /*
854dd52495fSSaurabh Misra * Wait until TX and RX finish their job.
855dd52495fSSaurabh Misra */
856dd52495fSSaurabh Misra (void) bfe_wait_bit(bfe, BFE_ENET_CTRL, BFE_ENET_DISABLE, 20, 1);
857dd52495fSSaurabh Misra
858dd52495fSSaurabh Misra /*
859dd52495fSSaurabh Misra * Disables DMA engine.
860dd52495fSSaurabh Misra */
861dd52495fSSaurabh Misra OUTL(bfe, BFE_DMARX_CTRL, 0);
862dd52495fSSaurabh Misra OUTL(bfe, BFE_DMATX_CTRL, 0);
863dd52495fSSaurabh Misra
864dd52495fSSaurabh Misra drv_usecwait(10);
865dd52495fSSaurabh Misra
866dd52495fSSaurabh Misra bfe->bfe_chip_state = BFE_CHIP_HALT;
867dd52495fSSaurabh Misra }
868dd52495fSSaurabh Misra
869dd52495fSSaurabh Misra static void
bfe_chip_restart(bfe_t * bfe)870dd52495fSSaurabh Misra bfe_chip_restart(bfe_t *bfe)
871dd52495fSSaurabh Misra {
872dd52495fSSaurabh Misra DTRACE_PROBE2(chip__restart, int, bfe->bfe_unit,
873dd52495fSSaurabh Misra int, bfe->bfe_chip_action);
874dd52495fSSaurabh Misra
875dd52495fSSaurabh Misra /*
876dd52495fSSaurabh Misra * Halt chip and PHY.
877dd52495fSSaurabh Misra */
878dd52495fSSaurabh Misra bfe_chip_halt(bfe);
879dd52495fSSaurabh Misra bfe_stop_phy(bfe);
880dd52495fSSaurabh Misra bfe->bfe_chip_state = BFE_CHIP_STOPPED;
881dd52495fSSaurabh Misra
882dd52495fSSaurabh Misra /*
883dd52495fSSaurabh Misra * Init variables.
884dd52495fSSaurabh Misra */
885dd52495fSSaurabh Misra bfe_init_vars(bfe);
886dd52495fSSaurabh Misra
887dd52495fSSaurabh Misra /*
888dd52495fSSaurabh Misra * Reset chip and start PHY.
889dd52495fSSaurabh Misra */
890dd52495fSSaurabh Misra bfe_chip_reset(bfe);
891dd52495fSSaurabh Misra
892dd52495fSSaurabh Misra /*
893dd52495fSSaurabh Misra * DMA descriptor rings.
894dd52495fSSaurabh Misra */
895dd52495fSSaurabh Misra bfe_tx_desc_init(&bfe->bfe_tx_ring);
896dd52495fSSaurabh Misra bfe_rx_desc_init(&bfe->bfe_rx_ring);
897dd52495fSSaurabh Misra
898dd52495fSSaurabh Misra bfe->bfe_chip_state = BFE_CHIP_ACTIVE;
899dd52495fSSaurabh Misra bfe_set_rx_mode(bfe);
900dd52495fSSaurabh Misra bfe_enable_chip_intrs(bfe);
901dd52495fSSaurabh Misra }
902dd52495fSSaurabh Misra
903dd52495fSSaurabh Misra /*
904dd52495fSSaurabh Misra * Disables core by stopping the clock.
905dd52495fSSaurabh Misra */
906dd52495fSSaurabh Misra static void
bfe_core_disable(bfe_t * bfe)907dd52495fSSaurabh Misra bfe_core_disable(bfe_t *bfe)
908dd52495fSSaurabh Misra {
909dd52495fSSaurabh Misra if ((INL(bfe, BFE_SBTMSLOW) & BFE_RESET))
910dd52495fSSaurabh Misra return;
911dd52495fSSaurabh Misra
912dd52495fSSaurabh Misra OUTL(bfe, BFE_SBTMSLOW, (BFE_REJECT | BFE_CLOCK));
913dd52495fSSaurabh Misra (void) bfe_wait_bit(bfe, BFE_SBTMSLOW, BFE_REJECT, 100, 0);
914dd52495fSSaurabh Misra (void) bfe_wait_bit(bfe, BFE_SBTMSHIGH, BFE_BUSY, 100, 1);
915dd52495fSSaurabh Misra OUTL(bfe, BFE_SBTMSLOW, (BFE_FGC | BFE_CLOCK | BFE_REJECT | BFE_RESET));
916dd52495fSSaurabh Misra FLUSH(bfe, BFE_SBTMSLOW);
917dd52495fSSaurabh Misra drv_usecwait(10);
918dd52495fSSaurabh Misra OUTL(bfe, BFE_SBTMSLOW, (BFE_REJECT | BFE_RESET));
919dd52495fSSaurabh Misra drv_usecwait(10);
920dd52495fSSaurabh Misra }
921dd52495fSSaurabh Misra
922dd52495fSSaurabh Misra /*
923dd52495fSSaurabh Misra * Resets core.
924dd52495fSSaurabh Misra */
925dd52495fSSaurabh Misra static void
bfe_core_reset(bfe_t * bfe)926dd52495fSSaurabh Misra bfe_core_reset(bfe_t *bfe)
927dd52495fSSaurabh Misra {
928dd52495fSSaurabh Misra uint32_t val;
929dd52495fSSaurabh Misra
930dd52495fSSaurabh Misra /*
931dd52495fSSaurabh Misra * First disable the core.
932dd52495fSSaurabh Misra */
933dd52495fSSaurabh Misra bfe_core_disable(bfe);
934dd52495fSSaurabh Misra
935dd52495fSSaurabh Misra OUTL(bfe, BFE_SBTMSLOW, (BFE_RESET | BFE_CLOCK | BFE_FGC));
936dd52495fSSaurabh Misra FLUSH(bfe, BFE_SBTMSLOW);
937dd52495fSSaurabh Misra drv_usecwait(1);
938dd52495fSSaurabh Misra
939dd52495fSSaurabh Misra if (INL(bfe, BFE_SBTMSHIGH) & BFE_SERR)
940dd52495fSSaurabh Misra OUTL(bfe, BFE_SBTMSHIGH, 0);
941dd52495fSSaurabh Misra
942dd52495fSSaurabh Misra val = INL(bfe, BFE_SBIMSTATE);
943dd52495fSSaurabh Misra if (val & (BFE_IBE | BFE_TO))
944dd52495fSSaurabh Misra OUTL(bfe, BFE_SBIMSTATE, val & ~(BFE_IBE | BFE_TO));
945dd52495fSSaurabh Misra
946dd52495fSSaurabh Misra OUTL(bfe, BFE_SBTMSLOW, (BFE_CLOCK | BFE_FGC));
947dd52495fSSaurabh Misra FLUSH(bfe, BFE_SBTMSLOW);
948dd52495fSSaurabh Misra drv_usecwait(1);
949dd52495fSSaurabh Misra
950dd52495fSSaurabh Misra OUTL(bfe, BFE_SBTMSLOW, BFE_CLOCK);
951dd52495fSSaurabh Misra FLUSH(bfe, BFE_SBTMSLOW);
952dd52495fSSaurabh Misra drv_usecwait(1);
953dd52495fSSaurabh Misra }
954dd52495fSSaurabh Misra
955dd52495fSSaurabh Misra static void
bfe_setup_config(bfe_t * bfe,uint32_t cores)956dd52495fSSaurabh Misra bfe_setup_config(bfe_t *bfe, uint32_t cores)
957dd52495fSSaurabh Misra {
958dd52495fSSaurabh Misra uint32_t bar_orig, val;
959dd52495fSSaurabh Misra
960dd52495fSSaurabh Misra /*
961dd52495fSSaurabh Misra * Change bar0 window to map sbtopci registers.
962dd52495fSSaurabh Misra */
963dd52495fSSaurabh Misra bar_orig = pci_config_get32(bfe->bfe_conf_handle, BFE_BAR0_WIN);
964dd52495fSSaurabh Misra pci_config_put32(bfe->bfe_conf_handle, BFE_BAR0_WIN, BFE_REG_PCI);
965dd52495fSSaurabh Misra
966dd52495fSSaurabh Misra /* Just read it and don't do anything */
967dd52495fSSaurabh Misra val = INL(bfe, BFE_SBIDHIGH) & BFE_IDH_CORE;
968dd52495fSSaurabh Misra
969dd52495fSSaurabh Misra val = INL(bfe, BFE_SBINTVEC);
970dd52495fSSaurabh Misra val |= cores;
971dd52495fSSaurabh Misra OUTL(bfe, BFE_SBINTVEC, val);
972dd52495fSSaurabh Misra
973dd52495fSSaurabh Misra val = INL(bfe, BFE_SSB_PCI_TRANS_2);
974dd52495fSSaurabh Misra val |= BFE_SSB_PCI_PREF | BFE_SSB_PCI_BURST;
975dd52495fSSaurabh Misra OUTL(bfe, BFE_SSB_PCI_TRANS_2, val);
976dd52495fSSaurabh Misra
977dd52495fSSaurabh Misra /*
978dd52495fSSaurabh Misra * Restore bar0 window mapping.
979dd52495fSSaurabh Misra */
980dd52495fSSaurabh Misra pci_config_put32(bfe->bfe_conf_handle, BFE_BAR0_WIN, bar_orig);
981dd52495fSSaurabh Misra }
982dd52495fSSaurabh Misra
983dd52495fSSaurabh Misra /*
984dd52495fSSaurabh Misra * Resets chip and starts PHY.
985dd52495fSSaurabh Misra */
986dd52495fSSaurabh Misra static void
bfe_chip_reset(bfe_t * bfe)987dd52495fSSaurabh Misra bfe_chip_reset(bfe_t *bfe)
988dd52495fSSaurabh Misra {
989dd52495fSSaurabh Misra uint32_t val;
990dd52495fSSaurabh Misra
991dd52495fSSaurabh Misra /* Set the interrupt vector for the enet core */
992dd52495fSSaurabh Misra bfe_setup_config(bfe, BFE_INTVEC_ENET0);
993dd52495fSSaurabh Misra
994dd52495fSSaurabh Misra /* check if core is up */
995dd52495fSSaurabh Misra val = INL(bfe, BFE_SBTMSLOW) &
996dd52495fSSaurabh Misra (BFE_RESET | BFE_REJECT | BFE_CLOCK);
997dd52495fSSaurabh Misra
998dd52495fSSaurabh Misra if (val == BFE_CLOCK) {
999dd52495fSSaurabh Misra OUTL(bfe, BFE_RCV_LAZY, 0);
1000dd52495fSSaurabh Misra OUTL(bfe, BFE_ENET_CTRL, BFE_ENET_DISABLE);
1001dd52495fSSaurabh Misra (void) bfe_wait_bit(bfe, BFE_ENET_CTRL,
1002dd52495fSSaurabh Misra BFE_ENET_DISABLE, 10, 1);
1003dd52495fSSaurabh Misra OUTL(bfe, BFE_DMATX_CTRL, 0);
1004dd52495fSSaurabh Misra FLUSH(bfe, BFE_DMARX_STAT);
1005dd52495fSSaurabh Misra drv_usecwait(20000); /* 20 milli seconds */
1006dd52495fSSaurabh Misra if (INL(bfe, BFE_DMARX_STAT) & BFE_STAT_EMASK) {
1007dd52495fSSaurabh Misra (void) bfe_wait_bit(bfe, BFE_DMARX_STAT, BFE_STAT_SIDLE,
1008dd52495fSSaurabh Misra 10, 0);
1009dd52495fSSaurabh Misra }
1010dd52495fSSaurabh Misra OUTL(bfe, BFE_DMARX_CTRL, 0);
1011dd52495fSSaurabh Misra }
1012dd52495fSSaurabh Misra
1013dd52495fSSaurabh Misra bfe_core_reset(bfe);
1014dd52495fSSaurabh Misra bfe_clear_stats(bfe);
1015dd52495fSSaurabh Misra
1016dd52495fSSaurabh Misra OUTL(bfe, BFE_MDIO_CTRL, 0x8d);
1017dd52495fSSaurabh Misra val = INL(bfe, BFE_DEVCTRL);
1018dd52495fSSaurabh Misra if (!(val & BFE_IPP))
1019dd52495fSSaurabh Misra OUTL(bfe, BFE_ENET_CTRL, BFE_ENET_EPSEL);
1020dd52495fSSaurabh Misra else if (INL(bfe, BFE_DEVCTRL & BFE_EPR)) {
1021dd52495fSSaurabh Misra OUTL_AND(bfe, BFE_DEVCTRL, ~BFE_EPR);
1022dd52495fSSaurabh Misra drv_usecwait(20000); /* 20 milli seconds */
1023dd52495fSSaurabh Misra }
1024dd52495fSSaurabh Misra
1025dd52495fSSaurabh Misra OUTL_OR(bfe, BFE_MAC_CTRL, BFE_CTRL_CRC32_ENAB | BFE_CTRL_LED);
1026dd52495fSSaurabh Misra
1027dd52495fSSaurabh Misra OUTL_AND(bfe, BFE_MAC_CTRL, ~BFE_CTRL_PDOWN);
1028dd52495fSSaurabh Misra
1029dd52495fSSaurabh Misra OUTL(bfe, BFE_RCV_LAZY, ((1 << BFE_LAZY_FC_SHIFT) &
1030dd52495fSSaurabh Misra BFE_LAZY_FC_MASK));
1031dd52495fSSaurabh Misra
1032dd52495fSSaurabh Misra OUTL_OR(bfe, BFE_RCV_LAZY, 0);
1033dd52495fSSaurabh Misra
1034dd52495fSSaurabh Misra OUTL(bfe, BFE_RXMAXLEN, bfe->bfe_rx_ring.r_buf_len);
1035dd52495fSSaurabh Misra OUTL(bfe, BFE_TXMAXLEN, bfe->bfe_tx_ring.r_buf_len);
1036dd52495fSSaurabh Misra
1037dd52495fSSaurabh Misra OUTL(bfe, BFE_TX_WMARK, 56);
1038dd52495fSSaurabh Misra
1039dd52495fSSaurabh Misra /* Program DMA channels */
1040dd52495fSSaurabh Misra OUTL(bfe, BFE_DMATX_CTRL, BFE_TX_CTRL_ENABLE);
1041dd52495fSSaurabh Misra
1042dd52495fSSaurabh Misra /*
1043dd52495fSSaurabh Misra * DMA addresses need to be added to BFE_PCI_DMA
1044dd52495fSSaurabh Misra */
1045dd52495fSSaurabh Misra OUTL(bfe, BFE_DMATX_ADDR,
1046dd52495fSSaurabh Misra bfe->bfe_tx_ring.r_desc_cookie.dmac_laddress + BFE_PCI_DMA);
1047dd52495fSSaurabh Misra
1048dd52495fSSaurabh Misra OUTL(bfe, BFE_DMARX_CTRL, (BFE_RX_OFFSET << BFE_RX_CTRL_ROSHIFT)
1049dd52495fSSaurabh Misra | BFE_RX_CTRL_ENABLE);
1050dd52495fSSaurabh Misra
1051dd52495fSSaurabh Misra OUTL(bfe, BFE_DMARX_ADDR,
1052dd52495fSSaurabh Misra bfe->bfe_rx_ring.r_desc_cookie.dmac_laddress + BFE_PCI_DMA);
1053dd52495fSSaurabh Misra
1054dd52495fSSaurabh Misra (void) bfe_startup_phy(bfe);
1055dd52495fSSaurabh Misra
1056dd52495fSSaurabh Misra bfe->bfe_chip_state = BFE_CHIP_INITIALIZED;
1057dd52495fSSaurabh Misra }
1058dd52495fSSaurabh Misra
1059dd52495fSSaurabh Misra /*
1060dd52495fSSaurabh Misra * It enables interrupts. Should be the last step while starting chip.
1061dd52495fSSaurabh Misra */
1062dd52495fSSaurabh Misra static void
bfe_enable_chip_intrs(bfe_t * bfe)1063dd52495fSSaurabh Misra bfe_enable_chip_intrs(bfe_t *bfe)
1064dd52495fSSaurabh Misra {
1065dd52495fSSaurabh Misra /* Enable the chip and core */
1066dd52495fSSaurabh Misra OUTL(bfe, BFE_ENET_CTRL, BFE_ENET_ENABLE);
1067dd52495fSSaurabh Misra
1068dd52495fSSaurabh Misra /* Enable interrupts */
1069dd52495fSSaurabh Misra OUTL(bfe, BFE_INTR_MASK, BFE_IMASK_DEF);
1070dd52495fSSaurabh Misra }
1071dd52495fSSaurabh Misra
1072dd52495fSSaurabh Misra /*
1073dd52495fSSaurabh Misra * Common code to take care of setting RX side mode (filter).
1074dd52495fSSaurabh Misra */
1075dd52495fSSaurabh Misra static void
bfe_set_rx_mode(bfe_t * bfe)1076dd52495fSSaurabh Misra bfe_set_rx_mode(bfe_t *bfe)
1077dd52495fSSaurabh Misra {
1078dd52495fSSaurabh Misra uint32_t val;
1079dd52495fSSaurabh Misra int i;
1080dd52495fSSaurabh Misra ether_addr_t mac[ETHERADDRL] = {0, 0, 0, 0, 0, 0};
1081dd52495fSSaurabh Misra
1082dd52495fSSaurabh Misra /*
1083dd52495fSSaurabh Misra * We don't touch RX filter if we were asked to suspend. It's fine
1084dd52495fSSaurabh Misra * if chip is not active (no interface is plumbed on us).
1085dd52495fSSaurabh Misra */
1086dd52495fSSaurabh Misra if (bfe->bfe_chip_state == BFE_CHIP_SUSPENDED)
1087dd52495fSSaurabh Misra return;
1088dd52495fSSaurabh Misra
1089dd52495fSSaurabh Misra val = INL(bfe, BFE_RXCONF);
1090dd52495fSSaurabh Misra
1091dd52495fSSaurabh Misra val &= ~BFE_RXCONF_PROMISC;
1092dd52495fSSaurabh Misra val &= ~BFE_RXCONF_DBCAST;
1093dd52495fSSaurabh Misra
1094dd52495fSSaurabh Misra if ((bfe->bfe_chip_mode & BFE_RX_MODE_ENABLE) == 0) {
1095dd52495fSSaurabh Misra OUTL(bfe, BFE_CAM_CTRL, 0);
1096dd52495fSSaurabh Misra FLUSH(bfe, BFE_CAM_CTRL);
1097dd52495fSSaurabh Misra } else if (bfe->bfe_chip_mode & BFE_RX_MODE_PROMISC) {
1098dd52495fSSaurabh Misra val |= BFE_RXCONF_PROMISC;
1099dd52495fSSaurabh Misra val &= ~BFE_RXCONF_DBCAST;
1100dd52495fSSaurabh Misra } else {
1101dd52495fSSaurabh Misra if (bfe->bfe_chip_state == BFE_CHIP_ACTIVE) {
1102dd52495fSSaurabh Misra /* Flush everything */
1103dd52495fSSaurabh Misra OUTL(bfe, BFE_RXCONF, val |
1104dd52495fSSaurabh Misra BFE_RXCONF_PROMISC | BFE_RXCONF_ALLMULTI);
1105dd52495fSSaurabh Misra FLUSH(bfe, BFE_RXCONF);
1106dd52495fSSaurabh Misra }
1107dd52495fSSaurabh Misra
1108dd52495fSSaurabh Misra /* Disable CAM */
1109dd52495fSSaurabh Misra OUTL(bfe, BFE_CAM_CTRL, 0);
1110dd52495fSSaurabh Misra FLUSH(bfe, BFE_CAM_CTRL);
1111dd52495fSSaurabh Misra
1112dd52495fSSaurabh Misra /*
1113dd52495fSSaurabh Misra * We receive all multicast packets.
1114dd52495fSSaurabh Misra */
1115dd52495fSSaurabh Misra val |= BFE_RXCONF_ALLMULTI;
1116dd52495fSSaurabh Misra
1117dd52495fSSaurabh Misra for (i = 0; i < BFE_MAX_MULTICAST_TABLE - 1; i++) {
1118dd52495fSSaurabh Misra bfe_cam_write(bfe, (uchar_t *)mac, i);
1119dd52495fSSaurabh Misra }
1120dd52495fSSaurabh Misra
1121dd52495fSSaurabh Misra bfe_cam_write(bfe, bfe->bfe_ether_addr, i);
1122dd52495fSSaurabh Misra
1123dd52495fSSaurabh Misra /* Enable CAM */
1124dd52495fSSaurabh Misra OUTL_OR(bfe, BFE_CAM_CTRL, BFE_CAM_ENABLE);
1125dd52495fSSaurabh Misra FLUSH(bfe, BFE_CAM_CTRL);
1126dd52495fSSaurabh Misra }
1127dd52495fSSaurabh Misra
1128dd52495fSSaurabh Misra DTRACE_PROBE2(rx__mode__filter, int, bfe->bfe_unit,
1129dd52495fSSaurabh Misra int, val);
1130dd52495fSSaurabh Misra
1131dd52495fSSaurabh Misra OUTL(bfe, BFE_RXCONF, val);
1132dd52495fSSaurabh Misra FLUSH(bfe, BFE_RXCONF);
1133dd52495fSSaurabh Misra }
1134dd52495fSSaurabh Misra
1135dd52495fSSaurabh Misra /*
1136dd52495fSSaurabh Misra * Reset various variable values to initial state.
1137dd52495fSSaurabh Misra */
1138dd52495fSSaurabh Misra static void
bfe_init_vars(bfe_t * bfe)1139dd52495fSSaurabh Misra bfe_init_vars(bfe_t *bfe)
1140dd52495fSSaurabh Misra {
1141dd52495fSSaurabh Misra bfe->bfe_chip_mode = BFE_RX_MODE_ENABLE;
1142dd52495fSSaurabh Misra
1143dd52495fSSaurabh Misra /* Initial assumption */
1144dd52495fSSaurabh Misra bfe->bfe_chip.link = LINK_STATE_UNKNOWN;
1145dd52495fSSaurabh Misra bfe->bfe_chip.speed = 0;
1146dd52495fSSaurabh Misra bfe->bfe_chip.duplex = LINK_DUPLEX_UNKNOWN;
1147dd52495fSSaurabh Misra
1148dd52495fSSaurabh Misra bfe->bfe_periodic_id = NULL;
1149dd52495fSSaurabh Misra bfe->bfe_chip_state = BFE_CHIP_UNINITIALIZED;
1150dd52495fSSaurabh Misra
1151dd52495fSSaurabh Misra bfe->bfe_tx_stall_time = 0;
1152dd52495fSSaurabh Misra }
1153dd52495fSSaurabh Misra
1154dd52495fSSaurabh Misra /*
1155dd52495fSSaurabh Misra * Initializes TX side descriptor entries (bfe_desc_t). Each descriptor entry
1156dd52495fSSaurabh Misra * has control (desc_ctl) and address (desc_addr) member.
1157dd52495fSSaurabh Misra */
1158dd52495fSSaurabh Misra static void
bfe_tx_desc_init(bfe_ring_t * r)1159dd52495fSSaurabh Misra bfe_tx_desc_init(bfe_ring_t *r)
1160dd52495fSSaurabh Misra {
1161dd52495fSSaurabh Misra int i;
1162dd52495fSSaurabh Misra uint32_t v;
1163dd52495fSSaurabh Misra
1164dd52495fSSaurabh Misra for (i = 0; i < r->r_ndesc; i++) {
1165dd52495fSSaurabh Misra PUT_DESC(r, (uint32_t *)&(r->r_desc[i].desc_ctl),
1166dd52495fSSaurabh Misra (r->r_buf_dma[i].len & BFE_DESC_LEN));
1167dd52495fSSaurabh Misra
1168dd52495fSSaurabh Misra /*
1169dd52495fSSaurabh Misra * DMA addresses need to be added to BFE_PCI_DMA
1170dd52495fSSaurabh Misra */
1171dd52495fSSaurabh Misra PUT_DESC(r, (uint32_t *)&(r->r_desc[i].desc_addr),
1172dd52495fSSaurabh Misra (r->r_buf_dma[i].cookie.dmac_laddress + BFE_PCI_DMA));
1173dd52495fSSaurabh Misra }
1174dd52495fSSaurabh Misra
1175dd52495fSSaurabh Misra v = GET_DESC(r, (uint32_t *)&(r->r_desc[i - 1].desc_ctl));
1176dd52495fSSaurabh Misra PUT_DESC(r, (uint32_t *)&(r->r_desc[i - 1].desc_ctl),
1177dd52495fSSaurabh Misra v | BFE_DESC_EOT);
1178dd52495fSSaurabh Misra
1179dd52495fSSaurabh Misra (void) SYNC_DESC(r, 0, r->r_ndesc, DDI_DMA_SYNC_FORDEV);
1180dd52495fSSaurabh Misra
1181dd52495fSSaurabh Misra r->r_curr_desc = 0;
1182dd52495fSSaurabh Misra r->r_avail_desc = TX_NUM_DESC;
1183dd52495fSSaurabh Misra r->r_cons_desc = 0;
1184dd52495fSSaurabh Misra }
1185dd52495fSSaurabh Misra
1186dd52495fSSaurabh Misra /*
1187dd52495fSSaurabh Misra * Initializes RX side descriptor entries (bfe_desc_t). Each descriptor entry
1188dd52495fSSaurabh Misra * has control (desc_ctl) and address (desc_addr) member.
1189dd52495fSSaurabh Misra */
1190dd52495fSSaurabh Misra static void
bfe_rx_desc_init(bfe_ring_t * r)1191dd52495fSSaurabh Misra bfe_rx_desc_init(bfe_ring_t *r)
1192dd52495fSSaurabh Misra {
1193dd52495fSSaurabh Misra int i;
1194dd52495fSSaurabh Misra uint32_t v;
1195dd52495fSSaurabh Misra
1196dd52495fSSaurabh Misra for (i = 0; i < r->r_ndesc; i++) {
1197dd52495fSSaurabh Misra PUT_DESC(r, (uint32_t *)&(r->r_desc[i].desc_ctl),
1198dd52495fSSaurabh Misra (r->r_buf_dma[i].len& BFE_DESC_LEN));
1199dd52495fSSaurabh Misra
1200dd52495fSSaurabh Misra PUT_DESC(r, (uint32_t *)&(r->r_desc[i].desc_addr),
1201dd52495fSSaurabh Misra (r->r_buf_dma[i].cookie.dmac_laddress + BFE_PCI_DMA));
1202dd52495fSSaurabh Misra
1203dd52495fSSaurabh Misra /* Initialize rx header (len, flags) */
1204dd52495fSSaurabh Misra bzero(r->r_buf_dma[i].addr, sizeof (bfe_rx_header_t));
1205dd52495fSSaurabh Misra
1206dd52495fSSaurabh Misra (void) SYNC_BUF(r, i, 0, sizeof (bfe_rx_header_t),
1207dd52495fSSaurabh Misra DDI_DMA_SYNC_FORDEV);
1208dd52495fSSaurabh Misra }
1209dd52495fSSaurabh Misra
1210dd52495fSSaurabh Misra v = GET_DESC(r, (uint32_t *)&(r->r_desc[i - 1].desc_ctl));
1211dd52495fSSaurabh Misra PUT_DESC(r, (uint32_t *)&(r->r_desc[i - 1].desc_ctl),
1212dd52495fSSaurabh Misra v | BFE_DESC_EOT);
1213dd52495fSSaurabh Misra
1214dd52495fSSaurabh Misra (void) SYNC_DESC(r, 0, r->r_ndesc, DDI_DMA_SYNC_FORDEV);
1215dd52495fSSaurabh Misra
1216dd52495fSSaurabh Misra /* TAIL of RX Descriptor */
1217dd52495fSSaurabh Misra OUTL(r->r_bfe, BFE_DMARX_PTR, ((i) * sizeof (bfe_desc_t)));
1218dd52495fSSaurabh Misra
1219dd52495fSSaurabh Misra r->r_curr_desc = 0;
1220dd52495fSSaurabh Misra r->r_avail_desc = RX_NUM_DESC;
1221dd52495fSSaurabh Misra }
1222dd52495fSSaurabh Misra
1223dd52495fSSaurabh Misra static int
bfe_chip_start(bfe_t * bfe)1224dd52495fSSaurabh Misra bfe_chip_start(bfe_t *bfe)
1225dd52495fSSaurabh Misra {
1226954c6b5eSSaurabh Misra ASSERT_ALL_LOCKS(bfe);
1227dd52495fSSaurabh Misra
1228dd52495fSSaurabh Misra /*
1229dd52495fSSaurabh Misra * Stop the chip first & then Reset the chip. At last enable interrupts.
1230dd52495fSSaurabh Misra */
1231dd52495fSSaurabh Misra bfe_chip_halt(bfe);
1232dd52495fSSaurabh Misra bfe_stop_phy(bfe);
1233dd52495fSSaurabh Misra
1234dd52495fSSaurabh Misra /*
1235dd52495fSSaurabh Misra * Reset chip and start PHY.
1236dd52495fSSaurabh Misra */
1237dd52495fSSaurabh Misra bfe_chip_reset(bfe);
1238dd52495fSSaurabh Misra
1239dd52495fSSaurabh Misra /*
1240dd52495fSSaurabh Misra * Initailize Descriptor Rings.
1241dd52495fSSaurabh Misra */
1242dd52495fSSaurabh Misra bfe_tx_desc_init(&bfe->bfe_tx_ring);
1243dd52495fSSaurabh Misra bfe_rx_desc_init(&bfe->bfe_rx_ring);
1244dd52495fSSaurabh Misra
1245dd52495fSSaurabh Misra bfe->bfe_chip_state = BFE_CHIP_ACTIVE;
1246dd52495fSSaurabh Misra bfe->bfe_chip_mode |= BFE_RX_MODE_ENABLE;
1247dd52495fSSaurabh Misra bfe_set_rx_mode(bfe);
1248dd52495fSSaurabh Misra bfe_enable_chip_intrs(bfe);
1249dd52495fSSaurabh Misra
1250dd52495fSSaurabh Misra /* Check link, speed and duplex mode */
1251dd52495fSSaurabh Misra (void) bfe_check_link(bfe);
1252dd52495fSSaurabh Misra
1253dd52495fSSaurabh Misra return (DDI_SUCCESS);
1254dd52495fSSaurabh Misra }
1255dd52495fSSaurabh Misra
1256dd52495fSSaurabh Misra
1257dd52495fSSaurabh Misra /*
1258dd52495fSSaurabh Misra * Clear chip statistics.
1259dd52495fSSaurabh Misra */
1260dd52495fSSaurabh Misra static void
bfe_clear_stats(bfe_t * bfe)1261dd52495fSSaurabh Misra bfe_clear_stats(bfe_t *bfe)
1262dd52495fSSaurabh Misra {
1263dd52495fSSaurabh Misra ulong_t r;
1264dd52495fSSaurabh Misra
1265dd52495fSSaurabh Misra OUTL(bfe, BFE_MIB_CTRL, BFE_MIB_CLR_ON_READ);
1266dd52495fSSaurabh Misra
1267dd52495fSSaurabh Misra /*
1268dd52495fSSaurabh Misra * Stat registers are cleared by reading.
1269dd52495fSSaurabh Misra */
1270dd52495fSSaurabh Misra for (r = BFE_TX_GOOD_O; r <= BFE_TX_PAUSE; r += 4)
1271dd52495fSSaurabh Misra (void) INL(bfe, r);
1272dd52495fSSaurabh Misra
1273dd52495fSSaurabh Misra for (r = BFE_RX_GOOD_O; r <= BFE_RX_NPAUSE; r += 4)
1274dd52495fSSaurabh Misra (void) INL(bfe, r);
1275dd52495fSSaurabh Misra }
1276dd52495fSSaurabh Misra
1277dd52495fSSaurabh Misra /*
1278dd52495fSSaurabh Misra * Collect chip statistics.
1279dd52495fSSaurabh Misra */
1280dd52495fSSaurabh Misra static void
bfe_gather_stats(bfe_t * bfe)1281dd52495fSSaurabh Misra bfe_gather_stats(bfe_t *bfe)
1282dd52495fSSaurabh Misra {
1283dd52495fSSaurabh Misra ulong_t r;
1284dd52495fSSaurabh Misra uint32_t *v;
1285dd52495fSSaurabh Misra uint32_t txerr = 0, rxerr = 0, coll = 0;
1286dd52495fSSaurabh Misra
1287dd52495fSSaurabh Misra v = &bfe->bfe_hw_stats.tx_good_octets;
1288dd52495fSSaurabh Misra for (r = BFE_TX_GOOD_O; r <= BFE_TX_PAUSE; r += 4) {
1289dd52495fSSaurabh Misra *v += INL(bfe, r);
1290dd52495fSSaurabh Misra v++;
1291dd52495fSSaurabh Misra }
1292dd52495fSSaurabh Misra
1293dd52495fSSaurabh Misra v = &bfe->bfe_hw_stats.rx_good_octets;
1294dd52495fSSaurabh Misra for (r = BFE_RX_GOOD_O; r <= BFE_RX_NPAUSE; r += 4) {
1295dd52495fSSaurabh Misra *v += INL(bfe, r);
1296dd52495fSSaurabh Misra v++;
1297dd52495fSSaurabh Misra }
1298dd52495fSSaurabh Misra
1299dd52495fSSaurabh Misra /*
1300dd52495fSSaurabh Misra * TX :
1301dd52495fSSaurabh Misra * -------
1302dd52495fSSaurabh Misra * tx_good_octets, tx_good_pkts, tx_octets
1303dd52495fSSaurabh Misra * tx_pkts, tx_broadcast_pkts, tx_multicast_pkts
1304dd52495fSSaurabh Misra * tx_len_64, tx_len_65_to_127, tx_len_128_to_255
1305dd52495fSSaurabh Misra * tx_len_256_to_511, tx_len_512_to_1023, tx_len_1024_to_max
1306dd52495fSSaurabh Misra * tx_jabber_pkts, tx_oversize_pkts, tx_fragment_pkts
1307dd52495fSSaurabh Misra * tx_underruns, tx_total_cols, tx_single_cols
1308dd52495fSSaurabh Misra * tx_multiple_cols, tx_excessive_cols, tx_late_cols
1309dd52495fSSaurabh Misra * tx_defered, tx_carrier_lost, tx_pause_pkts
1310dd52495fSSaurabh Misra *
1311dd52495fSSaurabh Misra * RX :
1312dd52495fSSaurabh Misra * -------
1313dd52495fSSaurabh Misra * rx_good_octets, rx_good_pkts, rx_octets
1314dd52495fSSaurabh Misra * rx_pkts, rx_broadcast_pkts, rx_multicast_pkts
1315dd52495fSSaurabh Misra * rx_len_64, rx_len_65_to_127, rx_len_128_to_255
1316dd52495fSSaurabh Misra * rx_len_256_to_511, rx_len_512_to_1023, rx_len_1024_to_max
1317dd52495fSSaurabh Misra * rx_jabber_pkts, rx_oversize_pkts, rx_fragment_pkts
1318dd52495fSSaurabh Misra * rx_missed_pkts, rx_crc_align_errs, rx_undersize
1319dd52495fSSaurabh Misra * rx_crc_errs, rx_align_errs, rx_symbol_errs
1320dd52495fSSaurabh Misra * rx_pause_pkts, rx_nonpause_pkts
1321dd52495fSSaurabh Misra */
1322dd52495fSSaurabh Misra
1323dd52495fSSaurabh Misra bfe->bfe_stats.ether_stat_carrier_errors =
1324dd52495fSSaurabh Misra bfe->bfe_hw_stats.tx_carrier_lost;
1325dd52495fSSaurabh Misra
1326dd52495fSSaurabh Misra /* txerr += bfe->bfe_hw_stats.tx_carrier_lost; */
1327dd52495fSSaurabh Misra
1328dd52495fSSaurabh Misra bfe->bfe_stats.ether_stat_ex_collisions =
1329dd52495fSSaurabh Misra bfe->bfe_hw_stats.tx_excessive_cols;
1330dd52495fSSaurabh Misra txerr += bfe->bfe_hw_stats.tx_excessive_cols;
1331dd52495fSSaurabh Misra coll += bfe->bfe_hw_stats.tx_excessive_cols;
1332dd52495fSSaurabh Misra
1333dd52495fSSaurabh Misra bfe->bfe_stats.ether_stat_fcs_errors =
1334dd52495fSSaurabh Misra bfe->bfe_hw_stats.rx_crc_errs;
1335dd52495fSSaurabh Misra rxerr += bfe->bfe_hw_stats.rx_crc_errs;
1336dd52495fSSaurabh Misra
1337dd52495fSSaurabh Misra bfe->bfe_stats.ether_stat_first_collisions =
1338dd52495fSSaurabh Misra bfe->bfe_hw_stats.tx_single_cols;
1339dd52495fSSaurabh Misra coll += bfe->bfe_hw_stats.tx_single_cols;
1340dd52495fSSaurabh Misra bfe->bfe_stats.ether_stat_multi_collisions =
1341dd52495fSSaurabh Misra bfe->bfe_hw_stats.tx_multiple_cols;
1342dd52495fSSaurabh Misra coll += bfe->bfe_hw_stats.tx_multiple_cols;
1343dd52495fSSaurabh Misra
1344dd52495fSSaurabh Misra bfe->bfe_stats.ether_stat_toolong_errors =
1345dd52495fSSaurabh Misra bfe->bfe_hw_stats.rx_oversize_pkts;
1346dd52495fSSaurabh Misra rxerr += bfe->bfe_hw_stats.rx_oversize_pkts;
1347dd52495fSSaurabh Misra
1348dd52495fSSaurabh Misra bfe->bfe_stats.ether_stat_tooshort_errors =
1349dd52495fSSaurabh Misra bfe->bfe_hw_stats.rx_undersize;
1350dd52495fSSaurabh Misra rxerr += bfe->bfe_hw_stats.rx_undersize;
1351dd52495fSSaurabh Misra
1352dd52495fSSaurabh Misra bfe->bfe_stats.ether_stat_tx_late_collisions +=
1353dd52495fSSaurabh Misra bfe->bfe_hw_stats.tx_late_cols;
1354dd52495fSSaurabh Misra
1355dd52495fSSaurabh Misra bfe->bfe_stats.ether_stat_defer_xmts +=
1356dd52495fSSaurabh Misra bfe->bfe_hw_stats.tx_defered;
1357dd52495fSSaurabh Misra
1358dd52495fSSaurabh Misra bfe->bfe_stats.ether_stat_macrcv_errors += rxerr;
1359dd52495fSSaurabh Misra bfe->bfe_stats.ether_stat_macxmt_errors += txerr;
1360dd52495fSSaurabh Misra
1361dd52495fSSaurabh Misra bfe->bfe_stats.collisions += coll;
1362dd52495fSSaurabh Misra }
1363dd52495fSSaurabh Misra
1364dd52495fSSaurabh Misra /*
1365dd52495fSSaurabh Misra * Gets the state for dladm command and all.
1366dd52495fSSaurabh Misra */
1367dd52495fSSaurabh Misra int
bfe_mac_getstat(void * arg,uint_t stat,uint64_t * val)1368dd52495fSSaurabh Misra bfe_mac_getstat(void *arg, uint_t stat, uint64_t *val)
1369dd52495fSSaurabh Misra {
1370dd52495fSSaurabh Misra bfe_t *bfe = (bfe_t *)arg;
1371dd52495fSSaurabh Misra uint64_t v;
1372dd52495fSSaurabh Misra int err = 0;
1373dd52495fSSaurabh Misra
1374dd52495fSSaurabh Misra rw_enter(&bfe->bfe_rwlock, RW_READER);
1375dd52495fSSaurabh Misra
1376dd52495fSSaurabh Misra
1377dd52495fSSaurabh Misra switch (stat) {
1378dd52495fSSaurabh Misra default:
1379dd52495fSSaurabh Misra err = ENOTSUP;
1380dd52495fSSaurabh Misra break;
1381dd52495fSSaurabh Misra
1382dd52495fSSaurabh Misra case MAC_STAT_IFSPEED:
1383dd52495fSSaurabh Misra /*
1384dd52495fSSaurabh Misra * MAC layer will ask for IFSPEED first and hence we
1385dd52495fSSaurabh Misra * collect it only once.
1386dd52495fSSaurabh Misra */
1387dd52495fSSaurabh Misra if (bfe->bfe_chip_state == BFE_CHIP_ACTIVE) {
1388dd52495fSSaurabh Misra /*
1389dd52495fSSaurabh Misra * Update stats from the hardware.
1390dd52495fSSaurabh Misra */
1391dd52495fSSaurabh Misra bfe_gather_stats(bfe);
1392dd52495fSSaurabh Misra }
1393dd52495fSSaurabh Misra v = bfe->bfe_chip.speed;
1394dd52495fSSaurabh Misra break;
1395dd52495fSSaurabh Misra
1396dd52495fSSaurabh Misra case ETHER_STAT_ADV_CAP_100T4:
1397dd52495fSSaurabh Misra v = bfe->bfe_adv_100T4;
1398dd52495fSSaurabh Misra break;
1399dd52495fSSaurabh Misra
1400dd52495fSSaurabh Misra case ETHER_STAT_ADV_CAP_100FDX:
1401dd52495fSSaurabh Misra v = (bfe->bfe_mii_anar & MII_ABILITY_100BASE_TX_FD) != 0;
1402dd52495fSSaurabh Misra break;
1403dd52495fSSaurabh Misra
1404dd52495fSSaurabh Misra case ETHER_STAT_ADV_CAP_100HDX:
1405dd52495fSSaurabh Misra v = (bfe->bfe_mii_anar & MII_ABILITY_100BASE_TX) != 0;
1406dd52495fSSaurabh Misra break;
1407dd52495fSSaurabh Misra
1408dd52495fSSaurabh Misra case ETHER_STAT_ADV_CAP_10FDX:
1409dd52495fSSaurabh Misra v = (bfe->bfe_mii_anar & MII_ABILITY_10BASE_T_FD) != 0;
1410dd52495fSSaurabh Misra break;
1411dd52495fSSaurabh Misra
1412dd52495fSSaurabh Misra case ETHER_STAT_ADV_CAP_10HDX:
1413dd52495fSSaurabh Misra v = (bfe->bfe_mii_anar & MII_ABILITY_10BASE_T) != 0;
1414dd52495fSSaurabh Misra break;
1415dd52495fSSaurabh Misra
1416dd52495fSSaurabh Misra case ETHER_STAT_ADV_CAP_ASMPAUSE:
1417dd52495fSSaurabh Misra v = 0;
1418dd52495fSSaurabh Misra break;
1419dd52495fSSaurabh Misra
1420dd52495fSSaurabh Misra case ETHER_STAT_ADV_CAP_AUTONEG:
1421dd52495fSSaurabh Misra v = bfe->bfe_adv_aneg;
1422dd52495fSSaurabh Misra break;
1423dd52495fSSaurabh Misra
1424dd52495fSSaurabh Misra case ETHER_STAT_ADV_CAP_PAUSE:
1425dd52495fSSaurabh Misra v = (bfe->bfe_mii_anar & MII_ABILITY_PAUSE) != 0;
1426dd52495fSSaurabh Misra break;
1427dd52495fSSaurabh Misra
1428dd52495fSSaurabh Misra case ETHER_STAT_ADV_REMFAULT:
1429dd52495fSSaurabh Misra v = (bfe->bfe_mii_anar & MII_AN_ADVERT_REMFAULT) != 0;
1430dd52495fSSaurabh Misra break;
1431dd52495fSSaurabh Misra
1432dd52495fSSaurabh Misra case ETHER_STAT_ALIGN_ERRORS:
1433dd52495fSSaurabh Misra /* MIB */
1434dd52495fSSaurabh Misra v = bfe->bfe_stats.ether_stat_align_errors;
1435dd52495fSSaurabh Misra break;
1436dd52495fSSaurabh Misra
1437dd52495fSSaurabh Misra case ETHER_STAT_CAP_100T4:
1438dd52495fSSaurabh Misra v = (bfe->bfe_mii_bmsr & MII_STATUS_100_BASE_T4) != 0;
1439dd52495fSSaurabh Misra break;
1440dd52495fSSaurabh Misra
1441dd52495fSSaurabh Misra case ETHER_STAT_CAP_100FDX:
1442dd52495fSSaurabh Misra v = (bfe->bfe_mii_bmsr & MII_STATUS_100_BASEX_FD) != 0;
1443dd52495fSSaurabh Misra break;
1444dd52495fSSaurabh Misra
1445dd52495fSSaurabh Misra case ETHER_STAT_CAP_100HDX:
1446dd52495fSSaurabh Misra v = (bfe->bfe_mii_bmsr & MII_STATUS_100_BASEX) != 0;
1447dd52495fSSaurabh Misra break;
1448dd52495fSSaurabh Misra
1449dd52495fSSaurabh Misra case ETHER_STAT_CAP_10FDX:
1450dd52495fSSaurabh Misra v = (bfe->bfe_mii_bmsr & MII_STATUS_10_FD) != 0;
1451dd52495fSSaurabh Misra break;
1452dd52495fSSaurabh Misra
1453dd52495fSSaurabh Misra case ETHER_STAT_CAP_10HDX:
1454dd52495fSSaurabh Misra v = (bfe->bfe_mii_bmsr & MII_STATUS_10) != 0;
1455dd52495fSSaurabh Misra break;
1456dd52495fSSaurabh Misra
1457dd52495fSSaurabh Misra case ETHER_STAT_CAP_ASMPAUSE:
1458dd52495fSSaurabh Misra v = 0;
1459dd52495fSSaurabh Misra break;
1460dd52495fSSaurabh Misra
1461dd52495fSSaurabh Misra case ETHER_STAT_CAP_AUTONEG:
1462dd52495fSSaurabh Misra v = ((bfe->bfe_mii_bmsr & MII_STATUS_CANAUTONEG) != 0);
1463dd52495fSSaurabh Misra break;
1464dd52495fSSaurabh Misra
1465dd52495fSSaurabh Misra case ETHER_STAT_CAP_PAUSE:
1466dd52495fSSaurabh Misra v = 1;
1467dd52495fSSaurabh Misra break;
1468dd52495fSSaurabh Misra
1469dd52495fSSaurabh Misra case ETHER_STAT_CAP_REMFAULT:
1470dd52495fSSaurabh Misra v = (bfe->bfe_mii_bmsr & MII_STATUS_REMFAULT) != 0;
1471dd52495fSSaurabh Misra break;
1472dd52495fSSaurabh Misra
1473dd52495fSSaurabh Misra case ETHER_STAT_CARRIER_ERRORS:
1474dd52495fSSaurabh Misra v = bfe->bfe_stats.ether_stat_carrier_errors;
1475dd52495fSSaurabh Misra break;
1476dd52495fSSaurabh Misra
1477dd52495fSSaurabh Misra case ETHER_STAT_JABBER_ERRORS:
1478dd52495fSSaurabh Misra err = ENOTSUP;
1479dd52495fSSaurabh Misra break;
1480dd52495fSSaurabh Misra
1481dd52495fSSaurabh Misra case ETHER_STAT_DEFER_XMTS:
1482dd52495fSSaurabh Misra v = bfe->bfe_stats.ether_stat_defer_xmts;
1483dd52495fSSaurabh Misra break;
1484dd52495fSSaurabh Misra
1485dd52495fSSaurabh Misra case ETHER_STAT_EX_COLLISIONS:
1486dd52495fSSaurabh Misra /* MIB */
1487dd52495fSSaurabh Misra v = bfe->bfe_stats.ether_stat_ex_collisions;
1488dd52495fSSaurabh Misra break;
1489dd52495fSSaurabh Misra
1490dd52495fSSaurabh Misra case ETHER_STAT_FCS_ERRORS:
1491dd52495fSSaurabh Misra /* MIB */
1492dd52495fSSaurabh Misra v = bfe->bfe_stats.ether_stat_fcs_errors;
1493dd52495fSSaurabh Misra break;
1494dd52495fSSaurabh Misra
1495dd52495fSSaurabh Misra case ETHER_STAT_FIRST_COLLISIONS:
1496dd52495fSSaurabh Misra /* MIB */
1497dd52495fSSaurabh Misra v = bfe->bfe_stats.ether_stat_first_collisions;
1498dd52495fSSaurabh Misra break;
1499dd52495fSSaurabh Misra
1500dd52495fSSaurabh Misra case ETHER_STAT_LINK_ASMPAUSE:
1501dd52495fSSaurabh Misra v = 0;
1502dd52495fSSaurabh Misra break;
1503dd52495fSSaurabh Misra
1504dd52495fSSaurabh Misra case ETHER_STAT_LINK_AUTONEG:
1505dd52495fSSaurabh Misra v = (bfe->bfe_mii_bmcr & MII_CONTROL_ANE) != 0 &&
1506dd52495fSSaurabh Misra (bfe->bfe_mii_bmsr & MII_STATUS_ANDONE) != 0;
1507dd52495fSSaurabh Misra break;
1508dd52495fSSaurabh Misra
1509dd52495fSSaurabh Misra case ETHER_STAT_LINK_DUPLEX:
1510dd52495fSSaurabh Misra v = bfe->bfe_chip.duplex;
1511dd52495fSSaurabh Misra break;
1512dd52495fSSaurabh Misra
1513dd52495fSSaurabh Misra case ETHER_STAT_LP_CAP_100T4:
1514dd52495fSSaurabh Misra v = (bfe->bfe_mii_anlpar & MII_ABILITY_100BASE_T4) != 0;
1515dd52495fSSaurabh Misra break;
1516dd52495fSSaurabh Misra
1517dd52495fSSaurabh Misra case ETHER_STAT_LP_CAP_100FDX:
1518dd52495fSSaurabh Misra v = (bfe->bfe_mii_anlpar & MII_ABILITY_100BASE_TX_FD) != 0;
1519dd52495fSSaurabh Misra break;
1520dd52495fSSaurabh Misra
1521dd52495fSSaurabh Misra case ETHER_STAT_LP_CAP_100HDX:
1522dd52495fSSaurabh Misra v = (bfe->bfe_mii_anlpar & MII_ABILITY_100BASE_TX) != 0;
1523dd52495fSSaurabh Misra break;
1524dd52495fSSaurabh Misra
1525dd52495fSSaurabh Misra case ETHER_STAT_LP_CAP_10FDX:
1526dd52495fSSaurabh Misra v = (bfe->bfe_mii_anlpar & MII_ABILITY_10BASE_T_FD) != 0;
1527dd52495fSSaurabh Misra break;
1528dd52495fSSaurabh Misra
1529dd52495fSSaurabh Misra case ETHER_STAT_LP_CAP_10HDX:
1530dd52495fSSaurabh Misra v = (bfe->bfe_mii_anlpar & MII_ABILITY_10BASE_T) != 0;
1531dd52495fSSaurabh Misra break;
1532dd52495fSSaurabh Misra
1533dd52495fSSaurabh Misra case ETHER_STAT_LP_CAP_ASMPAUSE:
1534dd52495fSSaurabh Misra v = 0;
1535dd52495fSSaurabh Misra break;
1536dd52495fSSaurabh Misra
1537dd52495fSSaurabh Misra case ETHER_STAT_LP_CAP_AUTONEG:
1538dd52495fSSaurabh Misra v = (bfe->bfe_mii_exp & MII_AN_EXP_LPCANAN) != 0;
1539dd52495fSSaurabh Misra break;
1540dd52495fSSaurabh Misra
1541dd52495fSSaurabh Misra case ETHER_STAT_LP_CAP_PAUSE:
1542dd52495fSSaurabh Misra v = (bfe->bfe_mii_anlpar & MII_ABILITY_PAUSE) != 0;
1543dd52495fSSaurabh Misra break;
1544dd52495fSSaurabh Misra
1545dd52495fSSaurabh Misra case ETHER_STAT_LP_REMFAULT:
1546dd52495fSSaurabh Misra v = (bfe->bfe_mii_anlpar & MII_STATUS_REMFAULT) != 0;
1547dd52495fSSaurabh Misra break;
1548dd52495fSSaurabh Misra
1549dd52495fSSaurabh Misra case ETHER_STAT_MACRCV_ERRORS:
1550dd52495fSSaurabh Misra v = bfe->bfe_stats.ether_stat_macrcv_errors;
1551dd52495fSSaurabh Misra break;
1552dd52495fSSaurabh Misra
1553dd52495fSSaurabh Misra case ETHER_STAT_MACXMT_ERRORS:
1554dd52495fSSaurabh Misra v = bfe->bfe_stats.ether_stat_macxmt_errors;
1555dd52495fSSaurabh Misra break;
1556dd52495fSSaurabh Misra
1557dd52495fSSaurabh Misra case ETHER_STAT_MULTI_COLLISIONS:
1558dd52495fSSaurabh Misra v = bfe->bfe_stats.ether_stat_multi_collisions;
1559dd52495fSSaurabh Misra break;
1560dd52495fSSaurabh Misra
1561dd52495fSSaurabh Misra case ETHER_STAT_SQE_ERRORS:
1562dd52495fSSaurabh Misra err = ENOTSUP;
1563dd52495fSSaurabh Misra break;
1564dd52495fSSaurabh Misra
1565dd52495fSSaurabh Misra case ETHER_STAT_TOOLONG_ERRORS:
1566dd52495fSSaurabh Misra v = bfe->bfe_stats.ether_stat_toolong_errors;
1567dd52495fSSaurabh Misra break;
1568dd52495fSSaurabh Misra
1569dd52495fSSaurabh Misra case ETHER_STAT_TOOSHORT_ERRORS:
1570dd52495fSSaurabh Misra v = bfe->bfe_stats.ether_stat_tooshort_errors;
1571dd52495fSSaurabh Misra break;
1572dd52495fSSaurabh Misra
1573dd52495fSSaurabh Misra case ETHER_STAT_TX_LATE_COLLISIONS:
1574dd52495fSSaurabh Misra v = bfe->bfe_stats.ether_stat_tx_late_collisions;
1575dd52495fSSaurabh Misra break;
1576dd52495fSSaurabh Misra
1577dd52495fSSaurabh Misra case ETHER_STAT_XCVR_ADDR:
1578dd52495fSSaurabh Misra v = bfe->bfe_phy_addr;
1579dd52495fSSaurabh Misra break;
1580dd52495fSSaurabh Misra
1581dd52495fSSaurabh Misra case ETHER_STAT_XCVR_ID:
1582dd52495fSSaurabh Misra v = bfe->bfe_phy_id;
1583dd52495fSSaurabh Misra break;
1584dd52495fSSaurabh Misra
1585dd52495fSSaurabh Misra case MAC_STAT_BRDCSTRCV:
1586dd52495fSSaurabh Misra v = bfe->bfe_stats.brdcstrcv;
1587dd52495fSSaurabh Misra break;
1588dd52495fSSaurabh Misra
1589dd52495fSSaurabh Misra case MAC_STAT_BRDCSTXMT:
1590dd52495fSSaurabh Misra v = bfe->bfe_stats.brdcstxmt;
1591dd52495fSSaurabh Misra break;
1592dd52495fSSaurabh Misra
1593dd52495fSSaurabh Misra case MAC_STAT_MULTIXMT:
1594dd52495fSSaurabh Misra v = bfe->bfe_stats.multixmt;
1595dd52495fSSaurabh Misra break;
1596dd52495fSSaurabh Misra
1597dd52495fSSaurabh Misra case MAC_STAT_COLLISIONS:
1598dd52495fSSaurabh Misra v = bfe->bfe_stats.collisions;
1599dd52495fSSaurabh Misra break;
1600dd52495fSSaurabh Misra
1601dd52495fSSaurabh Misra case MAC_STAT_IERRORS:
1602dd52495fSSaurabh Misra v = bfe->bfe_stats.ierrors;
1603dd52495fSSaurabh Misra break;
1604dd52495fSSaurabh Misra
1605dd52495fSSaurabh Misra case MAC_STAT_IPACKETS:
1606dd52495fSSaurabh Misra v = bfe->bfe_stats.ipackets;
1607dd52495fSSaurabh Misra break;
1608dd52495fSSaurabh Misra
1609dd52495fSSaurabh Misra case MAC_STAT_MULTIRCV:
1610dd52495fSSaurabh Misra v = bfe->bfe_stats.multircv;
1611dd52495fSSaurabh Misra break;
1612dd52495fSSaurabh Misra
1613dd52495fSSaurabh Misra case MAC_STAT_NORCVBUF:
1614dd52495fSSaurabh Misra v = bfe->bfe_stats.norcvbuf;
1615dd52495fSSaurabh Misra break;
1616dd52495fSSaurabh Misra
1617dd52495fSSaurabh Misra case MAC_STAT_NOXMTBUF:
1618dd52495fSSaurabh Misra v = bfe->bfe_stats.noxmtbuf;
1619dd52495fSSaurabh Misra break;
1620dd52495fSSaurabh Misra
1621dd52495fSSaurabh Misra case MAC_STAT_OBYTES:
1622dd52495fSSaurabh Misra v = bfe->bfe_stats.obytes;
1623dd52495fSSaurabh Misra break;
1624dd52495fSSaurabh Misra
1625dd52495fSSaurabh Misra case MAC_STAT_OERRORS:
1626dd52495fSSaurabh Misra /* MIB */
1627dd52495fSSaurabh Misra v = bfe->bfe_stats.ether_stat_macxmt_errors;
1628dd52495fSSaurabh Misra break;
1629dd52495fSSaurabh Misra
1630dd52495fSSaurabh Misra case MAC_STAT_OPACKETS:
1631dd52495fSSaurabh Misra v = bfe->bfe_stats.opackets;
1632dd52495fSSaurabh Misra break;
1633dd52495fSSaurabh Misra
1634dd52495fSSaurabh Misra case MAC_STAT_RBYTES:
1635dd52495fSSaurabh Misra v = bfe->bfe_stats.rbytes;
1636dd52495fSSaurabh Misra break;
1637dd52495fSSaurabh Misra
1638dd52495fSSaurabh Misra case MAC_STAT_UNDERFLOWS:
1639dd52495fSSaurabh Misra v = bfe->bfe_stats.underflows;
1640dd52495fSSaurabh Misra break;
1641dd52495fSSaurabh Misra
1642dd52495fSSaurabh Misra case MAC_STAT_OVERFLOWS:
1643dd52495fSSaurabh Misra v = bfe->bfe_stats.overflows;
1644dd52495fSSaurabh Misra break;
1645dd52495fSSaurabh Misra }
1646dd52495fSSaurabh Misra
1647dd52495fSSaurabh Misra rw_exit(&bfe->bfe_rwlock);
1648dd52495fSSaurabh Misra
1649dd52495fSSaurabh Misra *val = v;
1650dd52495fSSaurabh Misra return (err);
1651dd52495fSSaurabh Misra }
1652dd52495fSSaurabh Misra
1653dd52495fSSaurabh Misra int
bfe_mac_getprop(void * arg,const char * name,mac_prop_id_t num,uint_t sz,void * val)16540dc2366fSVenugopal Iyer bfe_mac_getprop(void *arg, const char *name, mac_prop_id_t num, uint_t sz,
16550dc2366fSVenugopal Iyer void *val)
1656dd52495fSSaurabh Misra {
1657dd52495fSSaurabh Misra bfe_t *bfe = (bfe_t *)arg;
1658dd52495fSSaurabh Misra int err = 0;
1659dd52495fSSaurabh Misra
1660dd52495fSSaurabh Misra switch (num) {
1661dd52495fSSaurabh Misra case MAC_PROP_DUPLEX:
16620dc2366fSVenugopal Iyer ASSERT(sz >= sizeof (link_duplex_t));
16630dc2366fSVenugopal Iyer bcopy(&bfe->bfe_chip.duplex, val, sizeof (link_duplex_t));
1664dd52495fSSaurabh Misra break;
1665dd52495fSSaurabh Misra
1666dd52495fSSaurabh Misra case MAC_PROP_SPEED:
16670dc2366fSVenugopal Iyer ASSERT(sz >= sizeof (uint64_t));
1668dd52495fSSaurabh Misra bcopy(&bfe->bfe_chip.speed, val, sizeof (uint64_t));
1669dd52495fSSaurabh Misra break;
1670dd52495fSSaurabh Misra
1671dd52495fSSaurabh Misra case MAC_PROP_AUTONEG:
16720dc2366fSVenugopal Iyer *(uint8_t *)val = bfe->bfe_adv_aneg;
1673dd52495fSSaurabh Misra break;
1674dd52495fSSaurabh Misra
1675dd52495fSSaurabh Misra case MAC_PROP_ADV_100FDX_CAP:
16760dc2366fSVenugopal Iyer *(uint8_t *)val = bfe->bfe_adv_100fdx;
1677dd52495fSSaurabh Misra break;
16780dc2366fSVenugopal Iyer
1679dd52495fSSaurabh Misra case MAC_PROP_EN_100FDX_CAP:
16800dc2366fSVenugopal Iyer *(uint8_t *)val = bfe->bfe_adv_100fdx;
1681dd52495fSSaurabh Misra break;
1682dd52495fSSaurabh Misra
1683dd52495fSSaurabh Misra case MAC_PROP_ADV_100HDX_CAP:
16840dc2366fSVenugopal Iyer *(uint8_t *)val = bfe->bfe_adv_100hdx;
1685dd52495fSSaurabh Misra break;
16860dc2366fSVenugopal Iyer
1687dd52495fSSaurabh Misra case MAC_PROP_EN_100HDX_CAP:
16880dc2366fSVenugopal Iyer *(uint8_t *)val = bfe->bfe_adv_100hdx;
1689dd52495fSSaurabh Misra break;
1690dd52495fSSaurabh Misra
1691dd52495fSSaurabh Misra case MAC_PROP_ADV_10FDX_CAP:
16920dc2366fSVenugopal Iyer *(uint8_t *)val = bfe->bfe_adv_10fdx;
1693dd52495fSSaurabh Misra break;
16940dc2366fSVenugopal Iyer
1695dd52495fSSaurabh Misra case MAC_PROP_EN_10FDX_CAP:
16960dc2366fSVenugopal Iyer *(uint8_t *)val = bfe->bfe_adv_10fdx;
1697dd52495fSSaurabh Misra break;
1698dd52495fSSaurabh Misra
1699dd52495fSSaurabh Misra case MAC_PROP_ADV_10HDX_CAP:
17000dc2366fSVenugopal Iyer *(uint8_t *)val = bfe->bfe_adv_10hdx;
1701dd52495fSSaurabh Misra break;
17020dc2366fSVenugopal Iyer
1703dd52495fSSaurabh Misra case MAC_PROP_EN_10HDX_CAP:
17040dc2366fSVenugopal Iyer *(uint8_t *)val = bfe->bfe_adv_10hdx;
1705dd52495fSSaurabh Misra break;
1706dd52495fSSaurabh Misra
1707dd52495fSSaurabh Misra case MAC_PROP_ADV_100T4_CAP:
17080dc2366fSVenugopal Iyer *(uint8_t *)val = bfe->bfe_adv_100T4;
1709dd52495fSSaurabh Misra break;
17100dc2366fSVenugopal Iyer
1711dd52495fSSaurabh Misra case MAC_PROP_EN_100T4_CAP:
17120dc2366fSVenugopal Iyer *(uint8_t *)val = bfe->bfe_adv_100T4;
1713dd52495fSSaurabh Misra break;
1714dd52495fSSaurabh Misra
1715dd52495fSSaurabh Misra default:
1716dd52495fSSaurabh Misra err = ENOTSUP;
1717dd52495fSSaurabh Misra }
1718dd52495fSSaurabh Misra
1719dd52495fSSaurabh Misra return (err);
1720dd52495fSSaurabh Misra }
1721dd52495fSSaurabh Misra
17220dc2366fSVenugopal Iyer
17230dc2366fSVenugopal Iyer static void
bfe_mac_propinfo(void * arg,const char * name,mac_prop_id_t num,mac_prop_info_handle_t prh)17240dc2366fSVenugopal Iyer bfe_mac_propinfo(void *arg, const char *name, mac_prop_id_t num,
17250dc2366fSVenugopal Iyer mac_prop_info_handle_t prh)
17260dc2366fSVenugopal Iyer {
17270dc2366fSVenugopal Iyer bfe_t *bfe = (bfe_t *)arg;
17280dc2366fSVenugopal Iyer
17290dc2366fSVenugopal Iyer switch (num) {
17300dc2366fSVenugopal Iyer case MAC_PROP_DUPLEX:
17310dc2366fSVenugopal Iyer case MAC_PROP_SPEED:
17320dc2366fSVenugopal Iyer case MAC_PROP_ADV_100FDX_CAP:
17330dc2366fSVenugopal Iyer case MAC_PROP_ADV_100HDX_CAP:
17340dc2366fSVenugopal Iyer case MAC_PROP_ADV_10FDX_CAP:
17350dc2366fSVenugopal Iyer case MAC_PROP_ADV_10HDX_CAP:
17360dc2366fSVenugopal Iyer case MAC_PROP_ADV_100T4_CAP:
17377a0c1e29SCrisson Guanghao Hu case MAC_PROP_EN_100T4_CAP:
17380dc2366fSVenugopal Iyer mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
17390dc2366fSVenugopal Iyer break;
17400dc2366fSVenugopal Iyer
17410dc2366fSVenugopal Iyer case MAC_PROP_AUTONEG:
17420dc2366fSVenugopal Iyer mac_prop_info_set_default_uint8(prh, bfe->bfe_cap_aneg);
17430dc2366fSVenugopal Iyer break;
17440dc2366fSVenugopal Iyer
17450dc2366fSVenugopal Iyer case MAC_PROP_EN_100FDX_CAP:
17460dc2366fSVenugopal Iyer mac_prop_info_set_default_uint8(prh, bfe->bfe_cap_100fdx);
17470dc2366fSVenugopal Iyer break;
17480dc2366fSVenugopal Iyer
17490dc2366fSVenugopal Iyer case MAC_PROP_EN_100HDX_CAP:
17500dc2366fSVenugopal Iyer mac_prop_info_set_default_uint8(prh, bfe->bfe_cap_100hdx);
17510dc2366fSVenugopal Iyer break;
17520dc2366fSVenugopal Iyer
17530dc2366fSVenugopal Iyer case MAC_PROP_EN_10FDX_CAP:
17540dc2366fSVenugopal Iyer mac_prop_info_set_default_uint8(prh, bfe->bfe_cap_10fdx);
17550dc2366fSVenugopal Iyer break;
17560dc2366fSVenugopal Iyer
17570dc2366fSVenugopal Iyer case MAC_PROP_EN_10HDX_CAP:
17580dc2366fSVenugopal Iyer mac_prop_info_set_default_uint8(prh, bfe->bfe_cap_10hdx);
17590dc2366fSVenugopal Iyer break;
17600dc2366fSVenugopal Iyer }
17610dc2366fSVenugopal Iyer }
17620dc2366fSVenugopal Iyer
17630dc2366fSVenugopal Iyer
1764dd52495fSSaurabh Misra /*ARGSUSED*/
1765dd52495fSSaurabh Misra int
bfe_mac_setprop(void * arg,const char * name,mac_prop_id_t num,uint_t sz,const void * val)1766dd52495fSSaurabh Misra bfe_mac_setprop(void *arg, const char *name, mac_prop_id_t num, uint_t sz,
1767dd52495fSSaurabh Misra const void *val)
1768dd52495fSSaurabh Misra {
1769dd52495fSSaurabh Misra bfe_t *bfe = (bfe_t *)arg;
1770dd52495fSSaurabh Misra uint8_t *advp;
1771dd52495fSSaurabh Misra uint8_t *capp;
1772dd52495fSSaurabh Misra int r = 0;
1773dd52495fSSaurabh Misra
1774dd52495fSSaurabh Misra switch (num) {
1775dd52495fSSaurabh Misra case MAC_PROP_EN_100FDX_CAP:
1776dd52495fSSaurabh Misra advp = &bfe->bfe_adv_100fdx;
1777dd52495fSSaurabh Misra capp = &bfe->bfe_cap_100fdx;
1778dd52495fSSaurabh Misra break;
1779dd52495fSSaurabh Misra
1780dd52495fSSaurabh Misra case MAC_PROP_EN_100HDX_CAP:
1781dd52495fSSaurabh Misra advp = &bfe->bfe_adv_100hdx;
1782dd52495fSSaurabh Misra capp = &bfe->bfe_cap_100hdx;
1783dd52495fSSaurabh Misra break;
1784dd52495fSSaurabh Misra
1785dd52495fSSaurabh Misra case MAC_PROP_EN_10FDX_CAP:
1786dd52495fSSaurabh Misra advp = &bfe->bfe_adv_10fdx;
1787dd52495fSSaurabh Misra capp = &bfe->bfe_cap_10fdx;
1788dd52495fSSaurabh Misra break;
1789dd52495fSSaurabh Misra
1790dd52495fSSaurabh Misra case MAC_PROP_EN_10HDX_CAP:
1791dd52495fSSaurabh Misra advp = &bfe->bfe_adv_10hdx;
1792dd52495fSSaurabh Misra capp = &bfe->bfe_cap_10hdx;
1793dd52495fSSaurabh Misra break;
1794dd52495fSSaurabh Misra
1795dd52495fSSaurabh Misra case MAC_PROP_AUTONEG:
1796dd52495fSSaurabh Misra advp = &bfe->bfe_adv_aneg;
1797dd52495fSSaurabh Misra capp = &bfe->bfe_cap_aneg;
1798dd52495fSSaurabh Misra break;
1799dd52495fSSaurabh Misra
1800dd52495fSSaurabh Misra default:
1801dd52495fSSaurabh Misra return (ENOTSUP);
1802dd52495fSSaurabh Misra }
1803dd52495fSSaurabh Misra
1804dd52495fSSaurabh Misra if (*capp == 0)
1805dd52495fSSaurabh Misra return (ENOTSUP);
1806dd52495fSSaurabh Misra
1807dd52495fSSaurabh Misra bfe_grab_locks(bfe);
1808dd52495fSSaurabh Misra
1809dd52495fSSaurabh Misra if (*advp != *(const uint8_t *)val) {
1810dd52495fSSaurabh Misra *advp = *(const uint8_t *)val;
1811dd52495fSSaurabh Misra
1812dd52495fSSaurabh Misra bfe->bfe_chip_action = BFE_ACTION_RESTART_SETPROP;
1813dd52495fSSaurabh Misra if (bfe->bfe_chip_state == BFE_CHIP_ACTIVE) {
1814dd52495fSSaurabh Misra /*
1815dd52495fSSaurabh Misra * We need to stop the timer before grabbing locks
1816dd52495fSSaurabh Misra * otherwise we can land-up in deadlock with untimeout.
1817dd52495fSSaurabh Misra */
1818dd52495fSSaurabh Misra bfe_stop_timer(bfe);
1819dd52495fSSaurabh Misra
1820dd52495fSSaurabh Misra bfe->bfe_chip_action |= BFE_ACTION_RESTART;
1821dd52495fSSaurabh Misra
1822dd52495fSSaurabh Misra bfe_chip_restart(bfe);
1823dd52495fSSaurabh Misra
1824dd52495fSSaurabh Misra /*
1825dd52495fSSaurabh Misra * We leave SETPROP because properties can be
1826dd52495fSSaurabh Misra * temporary.
1827dd52495fSSaurabh Misra */
1828dd52495fSSaurabh Misra bfe->bfe_chip_action &= ~(BFE_ACTION_RESTART);
1829dd52495fSSaurabh Misra r = 1;
1830dd52495fSSaurabh Misra }
1831dd52495fSSaurabh Misra }
1832dd52495fSSaurabh Misra
1833dd52495fSSaurabh Misra bfe_release_locks(bfe);
1834dd52495fSSaurabh Misra
1835dd52495fSSaurabh Misra /* kick-off a potential stopped downstream */
1836dd52495fSSaurabh Misra if (r)
1837dd52495fSSaurabh Misra mac_tx_update(bfe->bfe_machdl);
1838dd52495fSSaurabh Misra
1839dd52495fSSaurabh Misra return (0);
1840dd52495fSSaurabh Misra }
1841dd52495fSSaurabh Misra
1842dd52495fSSaurabh Misra
1843dd52495fSSaurabh Misra int
bfe_mac_set_ether_addr(void * arg,const uint8_t * ea)1844dd52495fSSaurabh Misra bfe_mac_set_ether_addr(void *arg, const uint8_t *ea)
1845dd52495fSSaurabh Misra {
1846dd52495fSSaurabh Misra bfe_t *bfe = (bfe_t *)arg;
1847dd52495fSSaurabh Misra
1848dd52495fSSaurabh Misra bfe_grab_locks(bfe);
1849dd52495fSSaurabh Misra bcopy(ea, bfe->bfe_ether_addr, ETHERADDRL);
1850dd52495fSSaurabh Misra bfe_set_rx_mode(bfe);
1851dd52495fSSaurabh Misra bfe_release_locks(bfe);
1852dd52495fSSaurabh Misra return (0);
1853dd52495fSSaurabh Misra }
1854dd52495fSSaurabh Misra
1855dd52495fSSaurabh Misra int
bfe_mac_start(void * arg)1856dd52495fSSaurabh Misra bfe_mac_start(void *arg)
1857dd52495fSSaurabh Misra {
1858dd52495fSSaurabh Misra bfe_t *bfe = (bfe_t *)arg;
1859dd52495fSSaurabh Misra
1860954c6b5eSSaurabh Misra bfe_grab_locks(bfe);
1861954c6b5eSSaurabh Misra if (bfe_chip_start(bfe) == DDI_FAILURE) {
1862954c6b5eSSaurabh Misra bfe_release_locks(bfe);
1863dd52495fSSaurabh Misra return (EINVAL);
1864954c6b5eSSaurabh Misra }
1865954c6b5eSSaurabh Misra
1866954c6b5eSSaurabh Misra bfe_release_locks(bfe);
1867954c6b5eSSaurabh Misra
1868954c6b5eSSaurabh Misra mac_tx_update(bfe->bfe_machdl);
1869dd52495fSSaurabh Misra
1870dd52495fSSaurabh Misra return (0);
1871dd52495fSSaurabh Misra }
1872dd52495fSSaurabh Misra
1873dd52495fSSaurabh Misra void
bfe_mac_stop(void * arg)1874dd52495fSSaurabh Misra bfe_mac_stop(void *arg)
1875dd52495fSSaurabh Misra {
1876dd52495fSSaurabh Misra bfe_t *bfe = (bfe_t *)arg;
1877dd52495fSSaurabh Misra
1878dd52495fSSaurabh Misra /*
1879dd52495fSSaurabh Misra * We need to stop the timer before grabbing locks otherwise
1880dd52495fSSaurabh Misra * we can land-up in deadlock with untimeout.
1881dd52495fSSaurabh Misra */
1882dd52495fSSaurabh Misra bfe_stop_timer(bfe);
1883dd52495fSSaurabh Misra
1884dd52495fSSaurabh Misra bfe_grab_locks(bfe);
1885dd52495fSSaurabh Misra
1886dd52495fSSaurabh Misra /*
1887dd52495fSSaurabh Misra * First halt the chip by disabling interrupts.
1888dd52495fSSaurabh Misra */
1889dd52495fSSaurabh Misra bfe_chip_halt(bfe);
1890dd52495fSSaurabh Misra bfe_stop_phy(bfe);
1891dd52495fSSaurabh Misra
1892dd52495fSSaurabh Misra bfe->bfe_chip_state = BFE_CHIP_STOPPED;
1893dd52495fSSaurabh Misra
1894dd52495fSSaurabh Misra /*
1895dd52495fSSaurabh Misra * This will leave the PHY running.
1896dd52495fSSaurabh Misra */
1897dd52495fSSaurabh Misra bfe_chip_reset(bfe);
1898dd52495fSSaurabh Misra
1899dd52495fSSaurabh Misra /*
1900dd52495fSSaurabh Misra * Disable RX register.
1901dd52495fSSaurabh Misra */
1902dd52495fSSaurabh Misra bfe->bfe_chip_mode &= ~BFE_RX_MODE_ENABLE;
1903dd52495fSSaurabh Misra bfe_set_rx_mode(bfe);
1904dd52495fSSaurabh Misra
1905dd52495fSSaurabh Misra bfe_release_locks(bfe);
1906dd52495fSSaurabh Misra }
1907dd52495fSSaurabh Misra
1908dd52495fSSaurabh Misra /*
1909dd52495fSSaurabh Misra * Send a packet down the wire.
1910dd52495fSSaurabh Misra */
1911dd52495fSSaurabh Misra static int
bfe_send_a_packet(bfe_t * bfe,mblk_t * mp)1912dd52495fSSaurabh Misra bfe_send_a_packet(bfe_t *bfe, mblk_t *mp)
1913dd52495fSSaurabh Misra {
1914dd52495fSSaurabh Misra bfe_ring_t *r = &bfe->bfe_tx_ring;
1915dd52495fSSaurabh Misra uint32_t cur = r->r_curr_desc;
1916dd52495fSSaurabh Misra uint32_t next;
1917dd52495fSSaurabh Misra size_t pktlen = msgsize(mp);
1918dd52495fSSaurabh Misra uchar_t *buf;
1919dd52495fSSaurabh Misra uint32_t v;
1920dd52495fSSaurabh Misra
1921dd52495fSSaurabh Misra ASSERT(MUTEX_HELD(&r->r_lock));
1922dd52495fSSaurabh Misra ASSERT(mp != NULL);
1923dd52495fSSaurabh Misra
1924dd52495fSSaurabh Misra if (pktlen > r->r_buf_len) {
1925dd52495fSSaurabh Misra freemsg(mp);
1926dd52495fSSaurabh Misra return (BFE_SUCCESS);
1927dd52495fSSaurabh Misra }
1928dd52495fSSaurabh Misra
1929dd52495fSSaurabh Misra /*
1930dd52495fSSaurabh Misra * There is a big reason why we don't check for '0'. It becomes easy
1931dd52495fSSaurabh Misra * for us to not roll over the ring since we are based on producer (tx)
1932dd52495fSSaurabh Misra * and consumer (reclaim by an interrupt) model. Especially when we
1933dd52495fSSaurabh Misra * run out of TX descriptor, chip will send a single interrupt and
1934dd52495fSSaurabh Misra * both producer and consumer counter will be same. So we keep a
1935dd52495fSSaurabh Misra * difference of 1 always.
1936dd52495fSSaurabh Misra */
1937dd52495fSSaurabh Misra if (r->r_avail_desc <= 1) {
1938dd52495fSSaurabh Misra bfe->bfe_stats.noxmtbuf++;
1939dd52495fSSaurabh Misra bfe->bfe_tx_resched = 1;
1940dd52495fSSaurabh Misra return (BFE_FAILURE);
1941dd52495fSSaurabh Misra }
1942dd52495fSSaurabh Misra
1943dd52495fSSaurabh Misra /*
1944dd52495fSSaurabh Misra * Get the DMA buffer to hold packet.
1945dd52495fSSaurabh Misra */
1946dd52495fSSaurabh Misra buf = (uchar_t *)r->r_buf_dma[cur].addr;
1947dd52495fSSaurabh Misra
1948dd52495fSSaurabh Misra mcopymsg(mp, buf); /* it also frees mp */
1949dd52495fSSaurabh Misra
1950dd52495fSSaurabh Misra /*
1951dd52495fSSaurabh Misra * Gather statistics.
1952dd52495fSSaurabh Misra */
1953dd52495fSSaurabh Misra if (buf[0] & 0x1) {
1954dd52495fSSaurabh Misra if (bcmp(buf, bfe_broadcast, ETHERADDRL) != 0)
1955dd52495fSSaurabh Misra bfe->bfe_stats.multixmt++;
1956dd52495fSSaurabh Misra else
1957dd52495fSSaurabh Misra bfe->bfe_stats.brdcstxmt++;
1958dd52495fSSaurabh Misra }
1959dd52495fSSaurabh Misra bfe->bfe_stats.opackets++;
1960dd52495fSSaurabh Misra bfe->bfe_stats.obytes += pktlen;
1961dd52495fSSaurabh Misra
1962dd52495fSSaurabh Misra
1963dd52495fSSaurabh Misra /*
1964dd52495fSSaurabh Misra * Program the DMA descriptor (start and end of frame are same).
1965dd52495fSSaurabh Misra */
1966dd52495fSSaurabh Misra next = cur;
1967dd52495fSSaurabh Misra v = (pktlen & BFE_DESC_LEN) | BFE_DESC_IOC | BFE_DESC_SOF |
1968dd52495fSSaurabh Misra BFE_DESC_EOF;
1969dd52495fSSaurabh Misra
1970dd52495fSSaurabh Misra if (cur == (TX_NUM_DESC - 1))
1971dd52495fSSaurabh Misra v |= BFE_DESC_EOT;
1972dd52495fSSaurabh Misra
1973dd52495fSSaurabh Misra PUT_DESC(r, (uint32_t *)&(r->r_desc[cur].desc_ctl), v);
1974dd52495fSSaurabh Misra
1975dd52495fSSaurabh Misra /*
1976dd52495fSSaurabh Misra * DMA addresses need to be added to BFE_PCI_DMA
1977dd52495fSSaurabh Misra */
1978dd52495fSSaurabh Misra PUT_DESC(r, (uint32_t *)&(r->r_desc[cur].desc_addr),
1979dd52495fSSaurabh Misra (r->r_buf_dma[cur].cookie.dmac_laddress + BFE_PCI_DMA));
1980dd52495fSSaurabh Misra
1981dd52495fSSaurabh Misra /*
1982dd52495fSSaurabh Misra * Sync the packet data for the device.
1983dd52495fSSaurabh Misra */
1984dd52495fSSaurabh Misra (void) SYNC_BUF(r, cur, 0, pktlen, DDI_DMA_SYNC_FORDEV);
1985dd52495fSSaurabh Misra
1986dd52495fSSaurabh Misra /* Move to next descriptor slot */
1987dd52495fSSaurabh Misra BFE_INC_SLOT(next, TX_NUM_DESC);
1988dd52495fSSaurabh Misra
1989dd52495fSSaurabh Misra (void) SYNC_DESC(r, 0, r->r_ndesc, DDI_DMA_SYNC_FORDEV);
1990dd52495fSSaurabh Misra
1991dd52495fSSaurabh Misra r->r_curr_desc = next;
1992dd52495fSSaurabh Misra
1993dd52495fSSaurabh Misra /*
1994dd52495fSSaurabh Misra * The order should be 1,2,3,... for BFE_DMATX_PTR if 0,1,2,3,...
1995dd52495fSSaurabh Misra * descriptor slot are being programmed.
1996dd52495fSSaurabh Misra */
1997dd52495fSSaurabh Misra OUTL(bfe, BFE_DMATX_PTR, next * sizeof (bfe_desc_t));
1998dd52495fSSaurabh Misra FLUSH(bfe, BFE_DMATX_PTR);
1999dd52495fSSaurabh Misra
2000dd52495fSSaurabh Misra r->r_avail_desc--;
2001dd52495fSSaurabh Misra
2002dd52495fSSaurabh Misra /*
2003dd52495fSSaurabh Misra * Let timeout know that it must reset the chip if a
2004dd52495fSSaurabh Misra * packet is not sent down the wire for more than 5 seconds.
2005dd52495fSSaurabh Misra */
2006dd52495fSSaurabh Misra bfe->bfe_tx_stall_time = gethrtime() + (5 * 1000000000ULL);
2007dd52495fSSaurabh Misra
2008dd52495fSSaurabh Misra return (BFE_SUCCESS);
2009dd52495fSSaurabh Misra }
2010dd52495fSSaurabh Misra
2011dd52495fSSaurabh Misra mblk_t *
bfe_mac_transmit_packet(void * arg,mblk_t * mp)2012dd52495fSSaurabh Misra bfe_mac_transmit_packet(void *arg, mblk_t *mp)
2013dd52495fSSaurabh Misra {
2014dd52495fSSaurabh Misra bfe_t *bfe = (bfe_t *)arg;
2015dd52495fSSaurabh Misra bfe_ring_t *r = &bfe->bfe_tx_ring;
2016dd52495fSSaurabh Misra mblk_t *nmp;
2017dd52495fSSaurabh Misra
2018dd52495fSSaurabh Misra mutex_enter(&r->r_lock);
2019dd52495fSSaurabh Misra
2020dd52495fSSaurabh Misra if (bfe->bfe_chip_state != BFE_CHIP_ACTIVE) {
2021954c6b5eSSaurabh Misra DTRACE_PROBE1(tx__chip__not__active, int, bfe->bfe_unit);
2022dd52495fSSaurabh Misra
2023dd52495fSSaurabh Misra freemsgchain(mp);
2024dd52495fSSaurabh Misra mutex_exit(&r->r_lock);
2025dd52495fSSaurabh Misra return (NULL);
2026dd52495fSSaurabh Misra }
2027dd52495fSSaurabh Misra
2028dd52495fSSaurabh Misra
2029dd52495fSSaurabh Misra while (mp != NULL) {
2030dd52495fSSaurabh Misra nmp = mp->b_next;
2031dd52495fSSaurabh Misra mp->b_next = NULL;
2032dd52495fSSaurabh Misra
2033dd52495fSSaurabh Misra if (bfe_send_a_packet(bfe, mp) == BFE_FAILURE) {
2034dd52495fSSaurabh Misra mp->b_next = nmp;
2035dd52495fSSaurabh Misra break;
2036dd52495fSSaurabh Misra }
2037dd52495fSSaurabh Misra mp = nmp;
2038dd52495fSSaurabh Misra }
2039dd52495fSSaurabh Misra
2040dd52495fSSaurabh Misra mutex_exit(&r->r_lock);
2041dd52495fSSaurabh Misra
2042dd52495fSSaurabh Misra return (mp);
2043dd52495fSSaurabh Misra }
2044dd52495fSSaurabh Misra
2045dd52495fSSaurabh Misra int
bfe_mac_set_promisc(void * arg,boolean_t promiscflag)2046dd52495fSSaurabh Misra bfe_mac_set_promisc(void *arg, boolean_t promiscflag)
2047dd52495fSSaurabh Misra {
2048dd52495fSSaurabh Misra bfe_t *bfe = (bfe_t *)arg;
2049dd52495fSSaurabh Misra
2050dd52495fSSaurabh Misra bfe_grab_locks(bfe);
2051dd52495fSSaurabh Misra if (bfe->bfe_chip_state != BFE_CHIP_ACTIVE) {
2052dd52495fSSaurabh Misra bfe_release_locks(bfe);
2053dd52495fSSaurabh Misra return (EIO);
2054dd52495fSSaurabh Misra }
2055dd52495fSSaurabh Misra
2056dd52495fSSaurabh Misra if (promiscflag) {
2057dd52495fSSaurabh Misra /* Set Promiscous on */
2058dd52495fSSaurabh Misra bfe->bfe_chip_mode |= BFE_RX_MODE_PROMISC;
2059dd52495fSSaurabh Misra } else {
2060dd52495fSSaurabh Misra bfe->bfe_chip_mode &= ~BFE_RX_MODE_PROMISC;
2061dd52495fSSaurabh Misra }
2062dd52495fSSaurabh Misra
2063dd52495fSSaurabh Misra bfe_set_rx_mode(bfe);
2064dd52495fSSaurabh Misra bfe_release_locks(bfe);
2065dd52495fSSaurabh Misra
2066dd52495fSSaurabh Misra return (0);
2067dd52495fSSaurabh Misra }
2068dd52495fSSaurabh Misra
2069dd52495fSSaurabh Misra int
bfe_mac_set_multicast(void * arg,boolean_t add,const uint8_t * macaddr)2070dd52495fSSaurabh Misra bfe_mac_set_multicast(void *arg, boolean_t add, const uint8_t *macaddr)
2071dd52495fSSaurabh Misra {
2072dd52495fSSaurabh Misra /*
2073dd52495fSSaurabh Misra * It was too much of pain to implement multicast in CAM. Instead
2074dd52495fSSaurabh Misra * we never disable multicast filter.
2075dd52495fSSaurabh Misra */
2076dd52495fSSaurabh Misra return (0);
2077dd52495fSSaurabh Misra }
2078dd52495fSSaurabh Misra
2079dd52495fSSaurabh Misra static mac_callbacks_t bfe_mac_callbacks = {
20800dc2366fSVenugopal Iyer MC_SETPROP | MC_GETPROP | MC_PROPINFO,
2081dd52495fSSaurabh Misra bfe_mac_getstat, /* gets stats */
2082dd52495fSSaurabh Misra bfe_mac_start, /* starts mac */
2083dd52495fSSaurabh Misra bfe_mac_stop, /* stops mac */
2084dd52495fSSaurabh Misra bfe_mac_set_promisc, /* sets promisc mode for snoop */
2085dd52495fSSaurabh Misra bfe_mac_set_multicast, /* multicast implementation */
2086dd52495fSSaurabh Misra bfe_mac_set_ether_addr, /* sets ethernet address (unicast) */
2087dd52495fSSaurabh Misra bfe_mac_transmit_packet, /* transmits packet */
20880dc2366fSVenugopal Iyer NULL,
2089dd52495fSSaurabh Misra NULL, /* ioctl */
2090dd52495fSSaurabh Misra NULL, /* getcap */
2091dd52495fSSaurabh Misra NULL, /* open */
2092dd52495fSSaurabh Misra NULL, /* close */
2093dd52495fSSaurabh Misra bfe_mac_setprop,
2094dd52495fSSaurabh Misra bfe_mac_getprop,
20950dc2366fSVenugopal Iyer bfe_mac_propinfo
2096dd52495fSSaurabh Misra };
2097dd52495fSSaurabh Misra
2098dd52495fSSaurabh Misra static void
bfe_error_handler(bfe_t * bfe,int intr_mask)2099dd52495fSSaurabh Misra bfe_error_handler(bfe_t *bfe, int intr_mask)
2100dd52495fSSaurabh Misra {
2101dd52495fSSaurabh Misra uint32_t v;
2102dd52495fSSaurabh Misra
2103dd52495fSSaurabh Misra if (intr_mask & BFE_ISTAT_RFO) {
2104dd52495fSSaurabh Misra bfe->bfe_stats.overflows++;
2105954c6b5eSSaurabh Misra bfe->bfe_chip_action |=
2106954c6b5eSSaurabh Misra (BFE_ACTION_RESTART | BFE_ACTION_RESTART_FAULT);
2107954c6b5eSSaurabh Misra goto action;
2108dd52495fSSaurabh Misra }
2109dd52495fSSaurabh Misra
2110dd52495fSSaurabh Misra if (intr_mask & BFE_ISTAT_TFU) {
2111dd52495fSSaurabh Misra bfe->bfe_stats.underflows++;
2112dd52495fSSaurabh Misra return;
2113dd52495fSSaurabh Misra }
2114dd52495fSSaurabh Misra
2115dd52495fSSaurabh Misra /* Descriptor Protocol Error */
2116dd52495fSSaurabh Misra if (intr_mask & BFE_ISTAT_DPE) {
2117dd52495fSSaurabh Misra bfe_error(bfe->bfe_dip,
2118dd52495fSSaurabh Misra "Descriptor Protocol Error. Halting Chip");
2119dd52495fSSaurabh Misra bfe->bfe_chip_action |=
2120dd52495fSSaurabh Misra (BFE_ACTION_RESTART | BFE_ACTION_RESTART_FAULT);
2121dd52495fSSaurabh Misra goto action;
2122dd52495fSSaurabh Misra }
2123dd52495fSSaurabh Misra
2124dd52495fSSaurabh Misra /* Descriptor Error */
2125*00d1eed8SRichard Lowe if (intr_mask & BFE_ISTAT_DSCE) {
2126dd52495fSSaurabh Misra bfe_error(bfe->bfe_dip, "Descriptor Error. Restarting Chip");
2127dd52495fSSaurabh Misra goto action;
2128dd52495fSSaurabh Misra }
2129dd52495fSSaurabh Misra
2130dd52495fSSaurabh Misra /* Receive Descr. Underflow */
2131dd52495fSSaurabh Misra if (intr_mask & BFE_ISTAT_RDU) {
2132dd52495fSSaurabh Misra bfe_error(bfe->bfe_dip,
2133dd52495fSSaurabh Misra "Receive Descriptor Underflow. Restarting Chip");
2134dd52495fSSaurabh Misra bfe->bfe_stats.ether_stat_macrcv_errors++;
2135dd52495fSSaurabh Misra bfe->bfe_chip_action |=
2136dd52495fSSaurabh Misra (BFE_ACTION_RESTART | BFE_ACTION_RESTART_FAULT);
2137dd52495fSSaurabh Misra goto action;
2138dd52495fSSaurabh Misra }
2139dd52495fSSaurabh Misra
2140dd52495fSSaurabh Misra v = INL(bfe, BFE_DMATX_STAT);
2141dd52495fSSaurabh Misra
2142dd52495fSSaurabh Misra /* Error while sending a packet */
2143dd52495fSSaurabh Misra if (v & BFE_STAT_EMASK) {
2144dd52495fSSaurabh Misra bfe->bfe_stats.ether_stat_macxmt_errors++;
2145dd52495fSSaurabh Misra bfe_error(bfe->bfe_dip,
2146dd52495fSSaurabh Misra "Error while sending a packet. Restarting Chip");
2147dd52495fSSaurabh Misra }
2148dd52495fSSaurabh Misra
2149dd52495fSSaurabh Misra /* Error while receiving a packet */
2150dd52495fSSaurabh Misra v = INL(bfe, BFE_DMARX_STAT);
2151dd52495fSSaurabh Misra if (v & BFE_RX_FLAG_ERRORS) {
2152dd52495fSSaurabh Misra bfe->bfe_stats.ierrors++;
2153dd52495fSSaurabh Misra bfe_error(bfe->bfe_dip,
2154dd52495fSSaurabh Misra "Error while receiving a packet. Restarting Chip");
2155dd52495fSSaurabh Misra }
2156dd52495fSSaurabh Misra
2157dd52495fSSaurabh Misra
2158dd52495fSSaurabh Misra bfe->bfe_chip_action |=
2159dd52495fSSaurabh Misra (BFE_ACTION_RESTART | BFE_ACTION_RESTART_FAULT);
2160dd52495fSSaurabh Misra
2161dd52495fSSaurabh Misra action:
2162dd52495fSSaurabh Misra bfe_chip_halt(bfe);
2163dd52495fSSaurabh Misra }
2164dd52495fSSaurabh Misra
2165dd52495fSSaurabh Misra /*
2166dd52495fSSaurabh Misra * It will recycle a RX descriptor slot.
2167dd52495fSSaurabh Misra */
2168dd52495fSSaurabh Misra static void
bfe_rx_desc_buf_reinit(bfe_t * bfe,uint_t slot)2169dd52495fSSaurabh Misra bfe_rx_desc_buf_reinit(bfe_t *bfe, uint_t slot)
2170dd52495fSSaurabh Misra {
2171dd52495fSSaurabh Misra bfe_ring_t *r = &bfe->bfe_rx_ring;
2172dd52495fSSaurabh Misra uint32_t v;
2173dd52495fSSaurabh Misra
2174dd52495fSSaurabh Misra slot %= RX_NUM_DESC;
2175dd52495fSSaurabh Misra
2176dd52495fSSaurabh Misra bzero(r->r_buf_dma[slot].addr, sizeof (bfe_rx_header_t));
2177dd52495fSSaurabh Misra
2178dd52495fSSaurabh Misra (void) SYNC_BUF(r, slot, 0, BFE_RX_OFFSET, DDI_DMA_SYNC_FORDEV);
2179dd52495fSSaurabh Misra
2180dd52495fSSaurabh Misra v = r->r_buf_dma[slot].len & BFE_DESC_LEN;
2181dd52495fSSaurabh Misra if (slot == (RX_NUM_DESC - 1))
2182dd52495fSSaurabh Misra v |= BFE_DESC_EOT;
2183dd52495fSSaurabh Misra
2184dd52495fSSaurabh Misra PUT_DESC(r, (uint32_t *)&(r->r_desc[slot].desc_ctl), v);
2185dd52495fSSaurabh Misra
2186dd52495fSSaurabh Misra /*
2187dd52495fSSaurabh Misra * DMA addresses need to be added to BFE_PCI_DMA
2188dd52495fSSaurabh Misra */
2189dd52495fSSaurabh Misra PUT_DESC(r, (uint32_t *)&(r->r_desc[slot].desc_addr),
2190dd52495fSSaurabh Misra (r->r_buf_dma[slot].cookie.dmac_laddress + BFE_PCI_DMA));
2191dd52495fSSaurabh Misra }
2192dd52495fSSaurabh Misra
2193dd52495fSSaurabh Misra /*
2194dd52495fSSaurabh Misra * Gets called from interrupt context to handle RX interrupt.
2195dd52495fSSaurabh Misra */
2196dd52495fSSaurabh Misra static mblk_t *
bfe_receive(bfe_t * bfe,int intr_mask)2197dd52495fSSaurabh Misra bfe_receive(bfe_t *bfe, int intr_mask)
2198dd52495fSSaurabh Misra {
2199dd52495fSSaurabh Misra int rxstat, current;
2200dd52495fSSaurabh Misra mblk_t *mp = NULL, *rx_head, *rx_tail;
2201dd52495fSSaurabh Misra uchar_t *rx_header;
2202dd52495fSSaurabh Misra uint16_t len;
2203dd52495fSSaurabh Misra uchar_t *bp;
2204dd52495fSSaurabh Misra bfe_ring_t *r = &bfe->bfe_rx_ring;
2205dd52495fSSaurabh Misra int i;
2206dd52495fSSaurabh Misra
2207dd52495fSSaurabh Misra rxstat = INL(bfe, BFE_DMARX_STAT);
2208dd52495fSSaurabh Misra current = (rxstat & BFE_STAT_CDMASK) / sizeof (bfe_desc_t);
2209dd52495fSSaurabh Misra i = r->r_curr_desc;
2210dd52495fSSaurabh Misra
2211dd52495fSSaurabh Misra rx_head = rx_tail = NULL;
2212dd52495fSSaurabh Misra
2213dd52495fSSaurabh Misra DTRACE_PROBE3(receive, int, bfe->bfe_unit,
2214dd52495fSSaurabh Misra int, r->r_curr_desc,
2215dd52495fSSaurabh Misra int, current);
2216dd52495fSSaurabh Misra
2217dd52495fSSaurabh Misra for (i = r->r_curr_desc; i != current;
2218dd52495fSSaurabh Misra BFE_INC_SLOT(i, RX_NUM_DESC)) {
2219dd52495fSSaurabh Misra
2220dd52495fSSaurabh Misra /*
2221dd52495fSSaurabh Misra * Sync the buffer associated with the descriptor table entry.
2222dd52495fSSaurabh Misra */
2223dd52495fSSaurabh Misra (void) SYNC_BUF(r, i, 0, r->r_buf_dma[i].len,
2224dd52495fSSaurabh Misra DDI_DMA_SYNC_FORKERNEL);
2225dd52495fSSaurabh Misra
2226dd52495fSSaurabh Misra rx_header = (void *)r->r_buf_dma[i].addr;
2227dd52495fSSaurabh Misra
2228dd52495fSSaurabh Misra /*
2229dd52495fSSaurabh Misra * We do this to make sure we are endian neutral. Chip is
2230dd52495fSSaurabh Misra * big endian.
2231dd52495fSSaurabh Misra *
2232dd52495fSSaurabh Misra * The header looks like :-
2233dd52495fSSaurabh Misra *
2234dd52495fSSaurabh Misra * Offset 0 -> uint16_t len
2235dd52495fSSaurabh Misra * Offset 2 -> uint16_t flags
2236dd52495fSSaurabh Misra * Offset 4 -> uint16_t pad[12]
2237dd52495fSSaurabh Misra */
2238dd52495fSSaurabh Misra len = (rx_header[1] << 8) | rx_header[0];
2239dd52495fSSaurabh Misra len -= 4; /* CRC bytes need to be removed */
2240dd52495fSSaurabh Misra
2241dd52495fSSaurabh Misra /*
2242dd52495fSSaurabh Misra * Don't receive this packet if pkt length is greater than
2243dd52495fSSaurabh Misra * MTU + VLAN_TAGSZ.
2244dd52495fSSaurabh Misra */
2245dd52495fSSaurabh Misra if (len > r->r_buf_len) {
2246dd52495fSSaurabh Misra /* Recycle slot for later use */
2247dd52495fSSaurabh Misra bfe_rx_desc_buf_reinit(bfe, i);
2248dd52495fSSaurabh Misra continue;
2249dd52495fSSaurabh Misra }
2250dd52495fSSaurabh Misra
2251dd52495fSSaurabh Misra if ((mp = allocb(len + VLAN_TAGSZ, BPRI_MED)) != NULL) {
2252dd52495fSSaurabh Misra mp->b_rptr += VLAN_TAGSZ;
2253dd52495fSSaurabh Misra bp = mp->b_rptr;
2254dd52495fSSaurabh Misra mp->b_wptr = bp + len;
2255dd52495fSSaurabh Misra
2256dd52495fSSaurabh Misra /* sizeof (bfe_rx_header_t) + 2 */
2257dd52495fSSaurabh Misra bcopy(r->r_buf_dma[i].addr +
2258dd52495fSSaurabh Misra BFE_RX_OFFSET, bp, len);
2259dd52495fSSaurabh Misra
2260dd52495fSSaurabh Misra mp->b_next = NULL;
2261dd52495fSSaurabh Misra if (rx_tail == NULL)
2262dd52495fSSaurabh Misra rx_head = rx_tail = mp;
2263dd52495fSSaurabh Misra else {
2264dd52495fSSaurabh Misra rx_tail->b_next = mp;
2265dd52495fSSaurabh Misra rx_tail = mp;
2266dd52495fSSaurabh Misra }
2267dd52495fSSaurabh Misra
2268dd52495fSSaurabh Misra /* Number of packets received so far */
2269dd52495fSSaurabh Misra bfe->bfe_stats.ipackets++;
2270dd52495fSSaurabh Misra
2271dd52495fSSaurabh Misra /* Total bytes of packets received so far */
2272dd52495fSSaurabh Misra bfe->bfe_stats.rbytes += len;
2273dd52495fSSaurabh Misra
2274dd52495fSSaurabh Misra if (bcmp(mp->b_rptr, bfe_broadcast, ETHERADDRL) == 0)
2275dd52495fSSaurabh Misra bfe->bfe_stats.brdcstrcv++;
2276dd52495fSSaurabh Misra else
2277dd52495fSSaurabh Misra bfe->bfe_stats.multircv++;
2278dd52495fSSaurabh Misra } else {
2279dd52495fSSaurabh Misra bfe->bfe_stats.norcvbuf++;
2280dd52495fSSaurabh Misra /* Recycle the slot for later use */
2281dd52495fSSaurabh Misra bfe_rx_desc_buf_reinit(bfe, i);
2282dd52495fSSaurabh Misra break;
2283dd52495fSSaurabh Misra }
2284dd52495fSSaurabh Misra
2285dd52495fSSaurabh Misra /*
2286dd52495fSSaurabh Misra * Reinitialize the current descriptor slot's buffer so that
2287dd52495fSSaurabh Misra * it can be reused.
2288dd52495fSSaurabh Misra */
2289dd52495fSSaurabh Misra bfe_rx_desc_buf_reinit(bfe, i);
2290dd52495fSSaurabh Misra }
2291dd52495fSSaurabh Misra
2292dd52495fSSaurabh Misra r->r_curr_desc = i;
2293dd52495fSSaurabh Misra
2294dd52495fSSaurabh Misra (void) SYNC_DESC(r, 0, r->r_ndesc, DDI_DMA_SYNC_FORDEV);
2295dd52495fSSaurabh Misra
2296dd52495fSSaurabh Misra return (rx_head);
2297dd52495fSSaurabh Misra }
2298dd52495fSSaurabh Misra
2299dd52495fSSaurabh Misra static int
bfe_tx_reclaim(bfe_ring_t * r)2300dd52495fSSaurabh Misra bfe_tx_reclaim(bfe_ring_t *r)
2301dd52495fSSaurabh Misra {
2302dd52495fSSaurabh Misra uint32_t cur, start;
2303dd52495fSSaurabh Misra uint32_t v;
2304dd52495fSSaurabh Misra
2305dd52495fSSaurabh Misra cur = INL(r->r_bfe, BFE_DMATX_STAT) & BFE_STAT_CDMASK;
2306dd52495fSSaurabh Misra cur = cur / sizeof (bfe_desc_t);
2307dd52495fSSaurabh Misra
2308dd52495fSSaurabh Misra /*
2309dd52495fSSaurabh Misra * Start with the last descriptor consumed by the chip.
2310dd52495fSSaurabh Misra */
2311dd52495fSSaurabh Misra start = r->r_cons_desc;
2312dd52495fSSaurabh Misra
2313dd52495fSSaurabh Misra DTRACE_PROBE3(tx__reclaim, int, r->r_bfe->bfe_unit,
2314dd52495fSSaurabh Misra int, start,
2315dd52495fSSaurabh Misra int, cur);
2316dd52495fSSaurabh Misra
2317dd52495fSSaurabh Misra /*
2318dd52495fSSaurabh Misra * There will be at least one descriptor to process.
2319dd52495fSSaurabh Misra */
2320dd52495fSSaurabh Misra while (start != cur) {
2321dd52495fSSaurabh Misra r->r_avail_desc++;
2322dd52495fSSaurabh Misra v = r->r_buf_dma[start].len & BFE_DESC_LEN;
2323dd52495fSSaurabh Misra if (start == (TX_NUM_DESC - 1))
2324dd52495fSSaurabh Misra v |= BFE_DESC_EOT;
2325dd52495fSSaurabh Misra
2326dd52495fSSaurabh Misra PUT_DESC(r, (uint32_t *)&(r->r_desc[start].desc_ctl), v);
2327dd52495fSSaurabh Misra PUT_DESC(r, (uint32_t *)&(r->r_desc[start].desc_addr),
2328dd52495fSSaurabh Misra (r->r_buf_dma[start].cookie.dmac_laddress + BFE_PCI_DMA));
2329dd52495fSSaurabh Misra
2330dd52495fSSaurabh Misra /* Move to next descriptor in TX ring */
2331dd52495fSSaurabh Misra BFE_INC_SLOT(start, TX_NUM_DESC);
2332dd52495fSSaurabh Misra }
2333dd52495fSSaurabh Misra
2334dd52495fSSaurabh Misra (void) ddi_dma_sync(r->r_desc_dma_handle,
2335dd52495fSSaurabh Misra 0, (r->r_ndesc * sizeof (bfe_desc_t)),
2336dd52495fSSaurabh Misra DDI_DMA_SYNC_FORDEV);
2337dd52495fSSaurabh Misra
2338dd52495fSSaurabh Misra r->r_cons_desc = start; /* consumed pointer */
2339dd52495fSSaurabh Misra r->r_bfe->bfe_tx_stall_time = 0;
2340dd52495fSSaurabh Misra
2341dd52495fSSaurabh Misra return (cur);
2342dd52495fSSaurabh Misra }
2343dd52495fSSaurabh Misra
2344dd52495fSSaurabh Misra static int
bfe_tx_done(bfe_t * bfe,int intr_mask)2345dd52495fSSaurabh Misra bfe_tx_done(bfe_t *bfe, int intr_mask)
2346dd52495fSSaurabh Misra {
2347dd52495fSSaurabh Misra bfe_ring_t *r = &bfe->bfe_tx_ring;
2348dd52495fSSaurabh Misra int resched = 0;
2349dd52495fSSaurabh Misra
2350dd52495fSSaurabh Misra mutex_enter(&r->r_lock);
2351dd52495fSSaurabh Misra (void) bfe_tx_reclaim(r);
2352dd52495fSSaurabh Misra
2353dd52495fSSaurabh Misra if (bfe->bfe_tx_resched) {
2354dd52495fSSaurabh Misra resched = 1;
2355dd52495fSSaurabh Misra bfe->bfe_tx_resched = 0;
2356dd52495fSSaurabh Misra }
2357dd52495fSSaurabh Misra mutex_exit(&r->r_lock);
2358dd52495fSSaurabh Misra
2359dd52495fSSaurabh Misra return (resched);
2360dd52495fSSaurabh Misra }
2361dd52495fSSaurabh Misra
2362dd52495fSSaurabh Misra /*
2363dd52495fSSaurabh Misra * ISR for interrupt handling
2364dd52495fSSaurabh Misra */
2365dd52495fSSaurabh Misra static uint_t
bfe_interrupt(caddr_t arg1,caddr_t arg2)2366dd52495fSSaurabh Misra bfe_interrupt(caddr_t arg1, caddr_t arg2)
2367dd52495fSSaurabh Misra {
2368dd52495fSSaurabh Misra bfe_t *bfe = (void *)arg1;
2369dd52495fSSaurabh Misra uint32_t intr_stat;
2370dd52495fSSaurabh Misra mblk_t *rx_head = NULL;
2371dd52495fSSaurabh Misra int resched = 0;
2372dd52495fSSaurabh Misra
2373dd52495fSSaurabh Misra /*
2374dd52495fSSaurabh Misra * Grab the lock to avoid stopping the chip while this interrupt
2375dd52495fSSaurabh Misra * is handled.
2376dd52495fSSaurabh Misra */
2377dd52495fSSaurabh Misra rw_enter(&bfe->bfe_rwlock, RW_READER);
2378dd52495fSSaurabh Misra
2379dd52495fSSaurabh Misra /*
2380dd52495fSSaurabh Misra * It's necessary to read intr stat again because masking interrupt
2381dd52495fSSaurabh Misra * register does not really mask interrupts coming from the chip.
2382dd52495fSSaurabh Misra */
2383dd52495fSSaurabh Misra intr_stat = INL(bfe, BFE_INTR_STAT);
2384dd52495fSSaurabh Misra intr_stat &= BFE_IMASK_DEF;
2385dd52495fSSaurabh Misra OUTL(bfe, BFE_INTR_STAT, intr_stat);
2386dd52495fSSaurabh Misra (void) INL(bfe, BFE_INTR_STAT);
2387dd52495fSSaurabh Misra
2388dd52495fSSaurabh Misra if (intr_stat == 0) {
2389dd52495fSSaurabh Misra rw_exit(&bfe->bfe_rwlock);
2390dd52495fSSaurabh Misra return (DDI_INTR_UNCLAIMED);
2391dd52495fSSaurabh Misra }
2392dd52495fSSaurabh Misra
2393954c6b5eSSaurabh Misra DTRACE_PROBE2(bfe__interrupt, int, bfe->bfe_unit,
2394954c6b5eSSaurabh Misra int, intr_stat);
2395954c6b5eSSaurabh Misra
2396dd52495fSSaurabh Misra if (bfe->bfe_chip_state != BFE_CHIP_ACTIVE) {
2397dd52495fSSaurabh Misra /*
2398dd52495fSSaurabh Misra * If chip is suspended then we just return.
2399dd52495fSSaurabh Misra */
2400dd52495fSSaurabh Misra if (bfe->bfe_chip_state == BFE_CHIP_SUSPENDED) {
2401dd52495fSSaurabh Misra rw_exit(&bfe->bfe_rwlock);
2402dd52495fSSaurabh Misra DTRACE_PROBE1(interrupt__chip__is__suspend, int,
2403dd52495fSSaurabh Misra bfe->bfe_unit);
2404dd52495fSSaurabh Misra return (DDI_INTR_CLAIMED);
2405dd52495fSSaurabh Misra }
2406dd52495fSSaurabh Misra
2407dd52495fSSaurabh Misra /*
2408dd52495fSSaurabh Misra * Halt the chip again i.e basically disable interrupts.
2409dd52495fSSaurabh Misra */
2410dd52495fSSaurabh Misra bfe_chip_halt(bfe);
2411dd52495fSSaurabh Misra rw_exit(&bfe->bfe_rwlock);
2412dd52495fSSaurabh Misra DTRACE_PROBE1(interrupt__chip__not__active, int,
2413dd52495fSSaurabh Misra bfe->bfe_unit);
2414dd52495fSSaurabh Misra return (DDI_INTR_CLAIMED);
2415dd52495fSSaurabh Misra }
2416dd52495fSSaurabh Misra
2417dd52495fSSaurabh Misra /* A packet was received */
2418dd52495fSSaurabh Misra if (intr_stat & BFE_ISTAT_RX) {
2419dd52495fSSaurabh Misra rx_head = bfe_receive(bfe, intr_stat);
2420dd52495fSSaurabh Misra }
2421dd52495fSSaurabh Misra
2422dd52495fSSaurabh Misra /* A packet was sent down the wire */
2423dd52495fSSaurabh Misra if (intr_stat & BFE_ISTAT_TX) {
2424dd52495fSSaurabh Misra resched = bfe_tx_done(bfe, intr_stat);
2425dd52495fSSaurabh Misra }
2426dd52495fSSaurabh Misra
2427dd52495fSSaurabh Misra /* There was an error */
2428dd52495fSSaurabh Misra if (intr_stat & BFE_ISTAT_ERRORS) {
2429dd52495fSSaurabh Misra bfe_error_handler(bfe, intr_stat);
2430dd52495fSSaurabh Misra }
2431dd52495fSSaurabh Misra
2432dd52495fSSaurabh Misra rw_exit(&bfe->bfe_rwlock);
2433dd52495fSSaurabh Misra
2434dd52495fSSaurabh Misra /*
2435dd52495fSSaurabh Misra * Pass the list of packets received from chip to MAC layer.
2436dd52495fSSaurabh Misra */
2437dd52495fSSaurabh Misra if (rx_head) {
2438dd52495fSSaurabh Misra mac_rx(bfe->bfe_machdl, 0, rx_head);
2439dd52495fSSaurabh Misra }
2440dd52495fSSaurabh Misra
2441dd52495fSSaurabh Misra /*
2442dd52495fSSaurabh Misra * Let the MAC start sending pkts to a potential stopped stream.
2443dd52495fSSaurabh Misra */
2444dd52495fSSaurabh Misra if (resched)
2445dd52495fSSaurabh Misra mac_tx_update(bfe->bfe_machdl);
2446dd52495fSSaurabh Misra
2447dd52495fSSaurabh Misra return (DDI_INTR_CLAIMED);
2448dd52495fSSaurabh Misra }
2449dd52495fSSaurabh Misra
2450dd52495fSSaurabh Misra /*
2451dd52495fSSaurabh Misra * Removes registered interrupt handler.
2452dd52495fSSaurabh Misra */
2453dd52495fSSaurabh Misra static void
bfe_remove_intr(bfe_t * bfe)2454dd52495fSSaurabh Misra bfe_remove_intr(bfe_t *bfe)
2455dd52495fSSaurabh Misra {
2456dd52495fSSaurabh Misra (void) ddi_intr_remove_handler(bfe->bfe_intrhdl);
2457dd52495fSSaurabh Misra (void) ddi_intr_free(bfe->bfe_intrhdl);
2458dd52495fSSaurabh Misra }
2459dd52495fSSaurabh Misra
2460dd52495fSSaurabh Misra /*
2461dd52495fSSaurabh Misra * Add an interrupt for the driver.
2462dd52495fSSaurabh Misra */
2463dd52495fSSaurabh Misra static int
bfe_add_intr(bfe_t * bfe)2464dd52495fSSaurabh Misra bfe_add_intr(bfe_t *bfe)
2465dd52495fSSaurabh Misra {
2466dd52495fSSaurabh Misra int nintrs = 1;
2467dd52495fSSaurabh Misra int ret;
2468dd52495fSSaurabh Misra
2469dd52495fSSaurabh Misra ret = ddi_intr_alloc(bfe->bfe_dip, &bfe->bfe_intrhdl,
2470dd52495fSSaurabh Misra DDI_INTR_TYPE_FIXED, /* type */
2471dd52495fSSaurabh Misra 0, /* inumber */
2472dd52495fSSaurabh Misra 1, /* count */
2473dd52495fSSaurabh Misra &nintrs, /* actual nintrs */
2474dd52495fSSaurabh Misra DDI_INTR_ALLOC_STRICT);
2475dd52495fSSaurabh Misra
2476dd52495fSSaurabh Misra if (ret != DDI_SUCCESS) {
2477dd52495fSSaurabh Misra bfe_error(bfe->bfe_dip, "ddi_intr_alloc() failed"
2478dd52495fSSaurabh Misra " : ret : %d", ret);
2479dd52495fSSaurabh Misra return (DDI_FAILURE);
2480dd52495fSSaurabh Misra }
2481dd52495fSSaurabh Misra
2482dd52495fSSaurabh Misra ret = ddi_intr_add_handler(bfe->bfe_intrhdl, bfe_interrupt, bfe, NULL);
2483dd52495fSSaurabh Misra if (ret != DDI_SUCCESS) {
2484dd52495fSSaurabh Misra bfe_error(bfe->bfe_dip, "ddi_intr_add_handler() failed");
2485dd52495fSSaurabh Misra (void) ddi_intr_free(bfe->bfe_intrhdl);
2486dd52495fSSaurabh Misra return (DDI_FAILURE);
2487dd52495fSSaurabh Misra }
2488dd52495fSSaurabh Misra
2489dd52495fSSaurabh Misra ret = ddi_intr_get_pri(bfe->bfe_intrhdl, &bfe->bfe_intrpri);
2490dd52495fSSaurabh Misra if (ret != DDI_SUCCESS) {
2491dd52495fSSaurabh Misra bfe_error(bfe->bfe_dip, "ddi_intr_get_pri() failed");
2492dd52495fSSaurabh Misra bfe_remove_intr(bfe);
2493dd52495fSSaurabh Misra return (DDI_FAILURE);
2494dd52495fSSaurabh Misra }
2495dd52495fSSaurabh Misra
2496dd52495fSSaurabh Misra return (DDI_SUCCESS);
2497dd52495fSSaurabh Misra }
2498dd52495fSSaurabh Misra
2499dd52495fSSaurabh Misra
2500dd52495fSSaurabh Misra /*
2501dd52495fSSaurabh Misra * Identify chipset family.
2502dd52495fSSaurabh Misra */
2503dd52495fSSaurabh Misra static int
bfe_identify_hardware(bfe_t * bfe)2504dd52495fSSaurabh Misra bfe_identify_hardware(bfe_t *bfe)
2505dd52495fSSaurabh Misra {
2506dd52495fSSaurabh Misra uint16_t vid, did;
2507dd52495fSSaurabh Misra int i;
2508dd52495fSSaurabh Misra
2509dd52495fSSaurabh Misra vid = pci_config_get16(bfe->bfe_conf_handle, PCI_CONF_VENID);
2510dd52495fSSaurabh Misra did = pci_config_get16(bfe->bfe_conf_handle, PCI_CONF_DEVID);
2511dd52495fSSaurabh Misra
2512dd52495fSSaurabh Misra for (i = 0; i < (sizeof (bfe_cards) / sizeof (bfe_cards_t)); i++) {
2513dd52495fSSaurabh Misra if (bfe_cards[i].vendor_id == vid &&
2514dd52495fSSaurabh Misra bfe_cards[i].device_id == did) {
2515dd52495fSSaurabh Misra return (BFE_SUCCESS);
2516dd52495fSSaurabh Misra }
2517dd52495fSSaurabh Misra }
2518dd52495fSSaurabh Misra
2519dd52495fSSaurabh Misra bfe_error(bfe->bfe_dip, "bfe driver is attaching to unknown pci%d,%d"
2520dd52495fSSaurabh Misra " vendor/device-id card", vid, did);
2521dd52495fSSaurabh Misra
2522dd52495fSSaurabh Misra return (BFE_SUCCESS);
2523dd52495fSSaurabh Misra }
2524dd52495fSSaurabh Misra
2525dd52495fSSaurabh Misra /*
2526dd52495fSSaurabh Misra * Maps device registers.
2527dd52495fSSaurabh Misra */
2528dd52495fSSaurabh Misra static int
bfe_regs_map(bfe_t * bfe)2529dd52495fSSaurabh Misra bfe_regs_map(bfe_t *bfe)
2530dd52495fSSaurabh Misra {
2531dd52495fSSaurabh Misra dev_info_t *dip = bfe->bfe_dip;
2532dd52495fSSaurabh Misra int ret;
2533dd52495fSSaurabh Misra
2534dd52495fSSaurabh Misra ret = ddi_regs_map_setup(dip, 1, &bfe->bfe_mem_regset.addr, 0, 0,
2535dd52495fSSaurabh Misra &bfe_dev_attr, &bfe->bfe_mem_regset.hdl);
2536dd52495fSSaurabh Misra
2537dd52495fSSaurabh Misra if (ret != DDI_SUCCESS) {
2538dd52495fSSaurabh Misra bfe_error(bfe->bfe_dip, "ddi_regs_map_setup failed");
2539dd52495fSSaurabh Misra return (DDI_FAILURE);
2540dd52495fSSaurabh Misra }
2541dd52495fSSaurabh Misra
2542dd52495fSSaurabh Misra return (DDI_SUCCESS);
2543dd52495fSSaurabh Misra }
2544dd52495fSSaurabh Misra
2545dd52495fSSaurabh Misra static void
bfe_unmap_regs(bfe_t * bfe)2546dd52495fSSaurabh Misra bfe_unmap_regs(bfe_t *bfe)
2547dd52495fSSaurabh Misra {
2548dd52495fSSaurabh Misra ddi_regs_map_free(&bfe->bfe_mem_regset.hdl);
2549dd52495fSSaurabh Misra }
2550dd52495fSSaurabh Misra
2551dd52495fSSaurabh Misra static int
bfe_get_chip_config(bfe_t * bfe)2552dd52495fSSaurabh Misra bfe_get_chip_config(bfe_t *bfe)
2553dd52495fSSaurabh Misra {
2554dd52495fSSaurabh Misra uint32_t prom[BFE_EEPROM_SIZE];
2555dd52495fSSaurabh Misra int i;
2556dd52495fSSaurabh Misra
2557dd52495fSSaurabh Misra /*
2558dd52495fSSaurabh Misra * Read EEPROM in prom[]
2559dd52495fSSaurabh Misra */
2560dd52495fSSaurabh Misra for (i = 0; i < BFE_EEPROM_SIZE; i++) {
2561dd52495fSSaurabh Misra prom[i] = INL(bfe, BFE_EEPROM_BASE + i * sizeof (uint32_t));
2562dd52495fSSaurabh Misra }
2563dd52495fSSaurabh Misra
2564dd52495fSSaurabh Misra bfe->bfe_dev_addr[0] = bfe->bfe_ether_addr[0] =
2565dd52495fSSaurabh Misra INB(bfe, BFE_EEPROM_BASE + 79);
2566dd52495fSSaurabh Misra
2567dd52495fSSaurabh Misra bfe->bfe_dev_addr[1] = bfe->bfe_ether_addr[1] =
2568dd52495fSSaurabh Misra INB(bfe, BFE_EEPROM_BASE + 78);
2569dd52495fSSaurabh Misra
2570dd52495fSSaurabh Misra bfe->bfe_dev_addr[2] = bfe->bfe_ether_addr[2] =
2571dd52495fSSaurabh Misra INB(bfe, BFE_EEPROM_BASE + 81);
2572dd52495fSSaurabh Misra
2573dd52495fSSaurabh Misra bfe->bfe_dev_addr[3] = bfe->bfe_ether_addr[3] =
2574dd52495fSSaurabh Misra INB(bfe, BFE_EEPROM_BASE + 80);
2575dd52495fSSaurabh Misra
2576dd52495fSSaurabh Misra bfe->bfe_dev_addr[4] = bfe->bfe_ether_addr[4] =
2577dd52495fSSaurabh Misra INB(bfe, BFE_EEPROM_BASE + 83);
2578dd52495fSSaurabh Misra
2579dd52495fSSaurabh Misra bfe->bfe_dev_addr[5] = bfe->bfe_ether_addr[5] =
2580dd52495fSSaurabh Misra INB(bfe, BFE_EEPROM_BASE + 82);
2581dd52495fSSaurabh Misra
2582dd52495fSSaurabh Misra bfe->bfe_phy_addr = -1;
2583dd52495fSSaurabh Misra
2584dd52495fSSaurabh Misra return (DDI_SUCCESS);
2585dd52495fSSaurabh Misra }
2586dd52495fSSaurabh Misra
2587dd52495fSSaurabh Misra /*
2588dd52495fSSaurabh Misra * Ring Management routines
2589dd52495fSSaurabh Misra */
2590dd52495fSSaurabh Misra static int
bfe_ring_buf_alloc(bfe_t * bfe,bfe_ring_t * r,int slot,int d)2591dd52495fSSaurabh Misra bfe_ring_buf_alloc(bfe_t *bfe, bfe_ring_t *r, int slot, int d)
2592dd52495fSSaurabh Misra {
2593dd52495fSSaurabh Misra int err;
2594dd52495fSSaurabh Misra uint_t count = 0;
2595dd52495fSSaurabh Misra
2596dd52495fSSaurabh Misra err = ddi_dma_alloc_handle(bfe->bfe_dip,
2597dd52495fSSaurabh Misra &bfe_dma_attr_buf, DDI_DMA_SLEEP, NULL,
2598dd52495fSSaurabh Misra &r->r_buf_dma[slot].handle);
2599dd52495fSSaurabh Misra
2600dd52495fSSaurabh Misra if (err != DDI_SUCCESS) {
2601dd52495fSSaurabh Misra bfe_error(bfe->bfe_dip, " bfe_ring_buf_alloc() :"
2602dd52495fSSaurabh Misra " alloc_handle failed");
2603dd52495fSSaurabh Misra goto fail0;
2604dd52495fSSaurabh Misra }
2605dd52495fSSaurabh Misra
2606dd52495fSSaurabh Misra err = ddi_dma_mem_alloc(r->r_buf_dma[slot].handle,
2607dd52495fSSaurabh Misra r->r_buf_len, &bfe_buf_attr, DDI_DMA_STREAMING,
2608dd52495fSSaurabh Misra DDI_DMA_SLEEP, NULL, &r->r_buf_dma[slot].addr,
2609dd52495fSSaurabh Misra &r->r_buf_dma[slot].len,
2610dd52495fSSaurabh Misra &r->r_buf_dma[slot].acchdl);
2611dd52495fSSaurabh Misra
2612dd52495fSSaurabh Misra if (err != DDI_SUCCESS) {
2613dd52495fSSaurabh Misra bfe_error(bfe->bfe_dip, " bfe_ring_buf_alloc() :"
2614dd52495fSSaurabh Misra " mem_alloc failed :%d", err);
2615dd52495fSSaurabh Misra goto fail1;
2616dd52495fSSaurabh Misra }
2617dd52495fSSaurabh Misra
2618dd52495fSSaurabh Misra err = ddi_dma_addr_bind_handle(r->r_buf_dma[slot].handle,
2619dd52495fSSaurabh Misra NULL, r->r_buf_dma[slot].addr,
2620dd52495fSSaurabh Misra r->r_buf_dma[slot].len,
2621dd52495fSSaurabh Misra (DDI_DMA_RDWR | DDI_DMA_STREAMING),
2622dd52495fSSaurabh Misra DDI_DMA_SLEEP, NULL,
2623dd52495fSSaurabh Misra &r->r_buf_dma[slot].cookie,
2624dd52495fSSaurabh Misra &count);
2625dd52495fSSaurabh Misra
2626dd52495fSSaurabh Misra if (err != DDI_DMA_MAPPED) {
2627dd52495fSSaurabh Misra bfe_error(bfe->bfe_dip, " bfe_ring_buf_alloc() :"
2628dd52495fSSaurabh Misra " bind_handle failed");
2629dd52495fSSaurabh Misra goto fail2;
2630dd52495fSSaurabh Misra }
2631dd52495fSSaurabh Misra
2632dd52495fSSaurabh Misra if (count > 1) {
2633dd52495fSSaurabh Misra bfe_error(bfe->bfe_dip, " bfe_ring_buf_alloc() :"
2634dd52495fSSaurabh Misra " more than one DMA cookie");
2635dd52495fSSaurabh Misra (void) ddi_dma_unbind_handle(r->r_buf_dma[slot].handle);
2636dd52495fSSaurabh Misra goto fail2;
2637dd52495fSSaurabh Misra }
2638dd52495fSSaurabh Misra
2639dd52495fSSaurabh Misra return (DDI_SUCCESS);
2640dd52495fSSaurabh Misra fail2:
2641dd52495fSSaurabh Misra ddi_dma_mem_free(&r->r_buf_dma[slot].acchdl);
2642dd52495fSSaurabh Misra fail1:
2643dd52495fSSaurabh Misra ddi_dma_free_handle(&r->r_buf_dma[slot].handle);
2644dd52495fSSaurabh Misra fail0:
2645dd52495fSSaurabh Misra return (DDI_FAILURE);
2646dd52495fSSaurabh Misra }
2647dd52495fSSaurabh Misra
2648dd52495fSSaurabh Misra static void
bfe_ring_buf_free(bfe_ring_t * r,int slot)2649dd52495fSSaurabh Misra bfe_ring_buf_free(bfe_ring_t *r, int slot)
2650dd52495fSSaurabh Misra {
2651dd52495fSSaurabh Misra if (r->r_buf_dma == NULL)
2652dd52495fSSaurabh Misra return;
2653dd52495fSSaurabh Misra
2654dd52495fSSaurabh Misra (void) ddi_dma_unbind_handle(r->r_buf_dma[slot].handle);
2655dd52495fSSaurabh Misra ddi_dma_mem_free(&r->r_buf_dma[slot].acchdl);
2656dd52495fSSaurabh Misra ddi_dma_free_handle(&r->r_buf_dma[slot].handle);
2657dd52495fSSaurabh Misra }
2658dd52495fSSaurabh Misra
2659dd52495fSSaurabh Misra static void
bfe_buffer_free(bfe_ring_t * r)2660dd52495fSSaurabh Misra bfe_buffer_free(bfe_ring_t *r)
2661dd52495fSSaurabh Misra {
2662dd52495fSSaurabh Misra int i;
2663dd52495fSSaurabh Misra
2664dd52495fSSaurabh Misra for (i = 0; i < r->r_ndesc; i++) {
2665dd52495fSSaurabh Misra bfe_ring_buf_free(r, i);
2666dd52495fSSaurabh Misra }
2667dd52495fSSaurabh Misra }
2668dd52495fSSaurabh Misra
2669dd52495fSSaurabh Misra static void
bfe_ring_desc_free(bfe_ring_t * r)2670dd52495fSSaurabh Misra bfe_ring_desc_free(bfe_ring_t *r)
2671dd52495fSSaurabh Misra {
2672dd52495fSSaurabh Misra (void) ddi_dma_unbind_handle(r->r_desc_dma_handle);
2673dd52495fSSaurabh Misra ddi_dma_mem_free(&r->r_desc_acc_handle);
2674dd52495fSSaurabh Misra ddi_dma_free_handle(&r->r_desc_dma_handle);
2675dd52495fSSaurabh Misra kmem_free(r->r_buf_dma, r->r_ndesc * sizeof (bfe_dma_t));
2676dd52495fSSaurabh Misra
2677dd52495fSSaurabh Misra r->r_buf_dma = NULL;
2678dd52495fSSaurabh Misra r->r_desc = NULL;
2679dd52495fSSaurabh Misra }
2680dd52495fSSaurabh Misra
2681dd52495fSSaurabh Misra
2682dd52495fSSaurabh Misra static int
bfe_ring_desc_alloc(bfe_t * bfe,bfe_ring_t * r,int d)2683dd52495fSSaurabh Misra bfe_ring_desc_alloc(bfe_t *bfe, bfe_ring_t *r, int d)
2684dd52495fSSaurabh Misra {
2685dd52495fSSaurabh Misra int err, i, fail = 0;
2686dd52495fSSaurabh Misra caddr_t ring;
2687dd52495fSSaurabh Misra size_t size_krnl = 0, size_dma = 0, ring_len = 0;
2688dd52495fSSaurabh Misra ddi_dma_cookie_t cookie;
2689dd52495fSSaurabh Misra uint_t count = 0;
2690dd52495fSSaurabh Misra
2691dd52495fSSaurabh Misra ASSERT(bfe != NULL);
2692dd52495fSSaurabh Misra
2693dd52495fSSaurabh Misra size_krnl = r->r_ndesc * sizeof (bfe_dma_t);
2694dd52495fSSaurabh Misra size_dma = r->r_ndesc * sizeof (bfe_desc_t);
2695dd52495fSSaurabh Misra r->r_buf_dma = kmem_zalloc(size_krnl, KM_SLEEP);
2696dd52495fSSaurabh Misra
2697dd52495fSSaurabh Misra
2698dd52495fSSaurabh Misra err = ddi_dma_alloc_handle(bfe->bfe_dip, &bfe_dma_attr_desc,
2699dd52495fSSaurabh Misra DDI_DMA_SLEEP, NULL, &r->r_desc_dma_handle);
2700dd52495fSSaurabh Misra
2701dd52495fSSaurabh Misra if (err != DDI_SUCCESS) {
2702dd52495fSSaurabh Misra bfe_error(bfe->bfe_dip, "bfe_ring_desc_alloc() failed on"
2703dd52495fSSaurabh Misra " ddi_dma_alloc_handle()");
2704dd52495fSSaurabh Misra kmem_free(r->r_buf_dma, size_krnl);
2705dd52495fSSaurabh Misra return (DDI_FAILURE);
2706dd52495fSSaurabh Misra }
2707dd52495fSSaurabh Misra
2708dd52495fSSaurabh Misra
2709dd52495fSSaurabh Misra err = ddi_dma_mem_alloc(r->r_desc_dma_handle,
2710dd52495fSSaurabh Misra size_dma, &bfe_buf_attr,
2711dd52495fSSaurabh Misra DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL,
2712dd52495fSSaurabh Misra &ring, &ring_len, &r->r_desc_acc_handle);
2713dd52495fSSaurabh Misra
2714dd52495fSSaurabh Misra if (err != DDI_SUCCESS) {
2715dd52495fSSaurabh Misra bfe_error(bfe->bfe_dip, "bfe_ring_desc_alloc() failed on"
2716dd52495fSSaurabh Misra " ddi_dma_mem_alloc()");
2717dd52495fSSaurabh Misra ddi_dma_free_handle(&r->r_desc_dma_handle);
2718dd52495fSSaurabh Misra kmem_free(r->r_buf_dma, size_krnl);
2719dd52495fSSaurabh Misra return (DDI_FAILURE);
2720dd52495fSSaurabh Misra }
2721dd52495fSSaurabh Misra
2722dd52495fSSaurabh Misra err = ddi_dma_addr_bind_handle(r->r_desc_dma_handle,
2723dd52495fSSaurabh Misra NULL, ring, ring_len,
2724dd52495fSSaurabh Misra DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
2725dd52495fSSaurabh Misra DDI_DMA_SLEEP, NULL,
2726dd52495fSSaurabh Misra &cookie, &count);
2727dd52495fSSaurabh Misra
2728dd52495fSSaurabh Misra if (err != DDI_SUCCESS) {
2729dd52495fSSaurabh Misra bfe_error(bfe->bfe_dip, "bfe_ring_desc_alloc() failed on"
2730dd52495fSSaurabh Misra " ddi_dma_addr_bind_handle()");
2731dd52495fSSaurabh Misra ddi_dma_mem_free(&r->r_desc_acc_handle);
2732dd52495fSSaurabh Misra ddi_dma_free_handle(&r->r_desc_dma_handle);
2733dd52495fSSaurabh Misra kmem_free(r->r_buf_dma, size_krnl);
2734dd52495fSSaurabh Misra return (DDI_FAILURE);
2735dd52495fSSaurabh Misra }
2736dd52495fSSaurabh Misra
2737dd52495fSSaurabh Misra /*
2738dd52495fSSaurabh Misra * We don't want to have multiple cookies. Descriptor should be
2739dd52495fSSaurabh Misra * aligned to PAGESIZE boundary.
2740dd52495fSSaurabh Misra */
2741dd52495fSSaurabh Misra ASSERT(count == 1);
2742dd52495fSSaurabh Misra
2743dd52495fSSaurabh Misra /* The actual descriptor for the ring */
2744dd52495fSSaurabh Misra r->r_desc_len = ring_len;
2745dd52495fSSaurabh Misra r->r_desc_cookie = cookie;
2746dd52495fSSaurabh Misra
2747dd52495fSSaurabh Misra r->r_desc = (void *)ring;
2748dd52495fSSaurabh Misra
2749dd52495fSSaurabh Misra bzero(r->r_desc, size_dma);
2750dd52495fSSaurabh Misra bzero(r->r_desc, ring_len);
2751dd52495fSSaurabh Misra
2752dd52495fSSaurabh Misra /* For each descriptor, allocate a DMA buffer */
2753dd52495fSSaurabh Misra fail = 0;
2754dd52495fSSaurabh Misra for (i = 0; i < r->r_ndesc; i++) {
2755dd52495fSSaurabh Misra if (bfe_ring_buf_alloc(bfe, r, i, d) != DDI_SUCCESS) {
2756dd52495fSSaurabh Misra i--;
2757dd52495fSSaurabh Misra fail = 1;
2758dd52495fSSaurabh Misra break;
2759dd52495fSSaurabh Misra }
2760dd52495fSSaurabh Misra }
2761dd52495fSSaurabh Misra
2762dd52495fSSaurabh Misra if (fail) {
2763dd52495fSSaurabh Misra while (i-- >= 0) {
2764dd52495fSSaurabh Misra bfe_ring_buf_free(r, i);
2765dd52495fSSaurabh Misra }
2766dd52495fSSaurabh Misra
2767dd52495fSSaurabh Misra /* We don't need the descriptor anymore */
2768dd52495fSSaurabh Misra bfe_ring_desc_free(r);
2769dd52495fSSaurabh Misra return (DDI_FAILURE);
2770dd52495fSSaurabh Misra }
2771dd52495fSSaurabh Misra
2772dd52495fSSaurabh Misra return (DDI_SUCCESS);
2773dd52495fSSaurabh Misra }
2774dd52495fSSaurabh Misra
2775dd52495fSSaurabh Misra static int
bfe_rings_alloc(bfe_t * bfe)2776dd52495fSSaurabh Misra bfe_rings_alloc(bfe_t *bfe)
2777dd52495fSSaurabh Misra {
2778dd52495fSSaurabh Misra /* TX */
2779dd52495fSSaurabh Misra mutex_init(&bfe->bfe_tx_ring.r_lock, NULL, MUTEX_DRIVER, NULL);
2780dd52495fSSaurabh Misra bfe->bfe_tx_ring.r_lockp = &bfe->bfe_tx_ring.r_lock;
2781dd52495fSSaurabh Misra bfe->bfe_tx_ring.r_buf_len = BFE_MTU + sizeof (struct ether_header) +
2782dd52495fSSaurabh Misra VLAN_TAGSZ + ETHERFCSL;
2783dd52495fSSaurabh Misra bfe->bfe_tx_ring.r_ndesc = TX_NUM_DESC;
2784dd52495fSSaurabh Misra bfe->bfe_tx_ring.r_bfe = bfe;
2785dd52495fSSaurabh Misra bfe->bfe_tx_ring.r_avail_desc = TX_NUM_DESC;
2786dd52495fSSaurabh Misra
2787dd52495fSSaurabh Misra /* RX */
2788dd52495fSSaurabh Misra mutex_init(&bfe->bfe_rx_ring.r_lock, NULL, MUTEX_DRIVER, NULL);
2789dd52495fSSaurabh Misra bfe->bfe_rx_ring.r_lockp = &bfe->bfe_rx_ring.r_lock;
2790dd52495fSSaurabh Misra bfe->bfe_rx_ring.r_buf_len = BFE_MTU + sizeof (struct ether_header) +
2791dd52495fSSaurabh Misra VLAN_TAGSZ + ETHERFCSL + RX_HEAD_ROOM;
2792dd52495fSSaurabh Misra bfe->bfe_rx_ring.r_ndesc = RX_NUM_DESC;
2793dd52495fSSaurabh Misra bfe->bfe_rx_ring.r_bfe = bfe;
2794dd52495fSSaurabh Misra bfe->bfe_rx_ring.r_avail_desc = RX_NUM_DESC;
2795dd52495fSSaurabh Misra
2796dd52495fSSaurabh Misra /* Allocate TX Ring */
2797dd52495fSSaurabh Misra if (bfe_ring_desc_alloc(bfe, &bfe->bfe_tx_ring,
2798dd52495fSSaurabh Misra DDI_DMA_WRITE) != DDI_SUCCESS)
2799dd52495fSSaurabh Misra return (DDI_FAILURE);
2800dd52495fSSaurabh Misra
2801dd52495fSSaurabh Misra /* Allocate RX Ring */
2802dd52495fSSaurabh Misra if (bfe_ring_desc_alloc(bfe, &bfe->bfe_rx_ring,
2803dd52495fSSaurabh Misra DDI_DMA_READ) != DDI_SUCCESS) {
2804dd52495fSSaurabh Misra cmn_err(CE_NOTE, "RX ring allocation failed");
2805dd52495fSSaurabh Misra bfe_ring_desc_free(&bfe->bfe_tx_ring);
2806dd52495fSSaurabh Misra return (DDI_FAILURE);
2807dd52495fSSaurabh Misra }
2808dd52495fSSaurabh Misra
2809dd52495fSSaurabh Misra bfe->bfe_tx_ring.r_flags = BFE_RING_ALLOCATED;
2810dd52495fSSaurabh Misra bfe->bfe_rx_ring.r_flags = BFE_RING_ALLOCATED;
2811dd52495fSSaurabh Misra
2812dd52495fSSaurabh Misra return (DDI_SUCCESS);
2813dd52495fSSaurabh Misra }
2814dd52495fSSaurabh Misra
2815dd52495fSSaurabh Misra static int
bfe_resume(dev_info_t * dip)2816dd52495fSSaurabh Misra bfe_resume(dev_info_t *dip)
2817dd52495fSSaurabh Misra {
2818dd52495fSSaurabh Misra bfe_t *bfe;
2819dd52495fSSaurabh Misra int err = DDI_SUCCESS;
2820dd52495fSSaurabh Misra
2821dd52495fSSaurabh Misra if ((bfe = ddi_get_driver_private(dip)) == NULL) {
2822dd52495fSSaurabh Misra bfe_error(dip, "Unexpected error (no driver private data)"
2823dd52495fSSaurabh Misra " while resume");
2824dd52495fSSaurabh Misra return (DDI_FAILURE);
2825dd52495fSSaurabh Misra }
2826dd52495fSSaurabh Misra
2827dd52495fSSaurabh Misra /*
2828dd52495fSSaurabh Misra * Grab all the locks first.
2829dd52495fSSaurabh Misra */
2830dd52495fSSaurabh Misra bfe_grab_locks(bfe);
2831dd52495fSSaurabh Misra bfe->bfe_chip_state = BFE_CHIP_RESUME;
2832dd52495fSSaurabh Misra
2833dd52495fSSaurabh Misra bfe_init_vars(bfe);
2834dd52495fSSaurabh Misra /* PHY will also start running */
2835dd52495fSSaurabh Misra bfe_chip_reset(bfe);
2836dd52495fSSaurabh Misra if (bfe_chip_start(bfe) == DDI_FAILURE) {
2837dd52495fSSaurabh Misra bfe_error(dip, "Could not resume chip");
2838dd52495fSSaurabh Misra err = DDI_FAILURE;
2839dd52495fSSaurabh Misra }
2840954c6b5eSSaurabh Misra
2841dd52495fSSaurabh Misra bfe_release_locks(bfe);
2842954c6b5eSSaurabh Misra
2843954c6b5eSSaurabh Misra if (err == DDI_SUCCESS)
2844954c6b5eSSaurabh Misra mac_tx_update(bfe->bfe_machdl);
2845954c6b5eSSaurabh Misra
2846dd52495fSSaurabh Misra return (err);
2847dd52495fSSaurabh Misra }
2848dd52495fSSaurabh Misra
2849dd52495fSSaurabh Misra static int
bfe_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)2850dd52495fSSaurabh Misra bfe_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
2851dd52495fSSaurabh Misra {
2852dd52495fSSaurabh Misra int unit;
2853dd52495fSSaurabh Misra bfe_t *bfe;
2854dd52495fSSaurabh Misra mac_register_t *macreg;
2855dd52495fSSaurabh Misra int ret;
2856dd52495fSSaurabh Misra
2857dd52495fSSaurabh Misra switch (cmd) {
2858dd52495fSSaurabh Misra case DDI_RESUME:
2859dd52495fSSaurabh Misra return (bfe_resume(dip));
2860dd52495fSSaurabh Misra
2861dd52495fSSaurabh Misra case DDI_ATTACH:
2862dd52495fSSaurabh Misra break;
2863dd52495fSSaurabh Misra
2864dd52495fSSaurabh Misra default:
2865dd52495fSSaurabh Misra return (DDI_FAILURE);
2866dd52495fSSaurabh Misra }
2867dd52495fSSaurabh Misra
2868dd52495fSSaurabh Misra
2869dd52495fSSaurabh Misra unit = ddi_get_instance(dip);
2870dd52495fSSaurabh Misra
2871dd52495fSSaurabh Misra bfe = kmem_zalloc(sizeof (bfe_t), KM_SLEEP);
2872dd52495fSSaurabh Misra bfe->bfe_dip = dip;
2873dd52495fSSaurabh Misra bfe->bfe_unit = unit;
2874dd52495fSSaurabh Misra
2875dd52495fSSaurabh Misra if (pci_config_setup(dip, &bfe->bfe_conf_handle) != DDI_SUCCESS) {
2876dd52495fSSaurabh Misra bfe_error(dip, "pci_config_setup failed");
2877dd52495fSSaurabh Misra goto fail0;
2878dd52495fSSaurabh Misra }
2879dd52495fSSaurabh Misra
2880dd52495fSSaurabh Misra /*
2881dd52495fSSaurabh Misra * Enable IO space, Bus Master and Memory Space accessess.
2882dd52495fSSaurabh Misra */
2883dd52495fSSaurabh Misra ret = pci_config_get16(bfe->bfe_conf_handle, PCI_CONF_COMM);
2884dd52495fSSaurabh Misra pci_config_put16(bfe->bfe_conf_handle, PCI_CONF_COMM,
2885dd52495fSSaurabh Misra PCI_COMM_IO | PCI_COMM_MAE | PCI_COMM_ME | ret);
2886dd52495fSSaurabh Misra
2887dd52495fSSaurabh Misra ddi_set_driver_private(dip, bfe);
2888dd52495fSSaurabh Misra
2889dd52495fSSaurabh Misra /* Identify hardware */
2890dd52495fSSaurabh Misra if (bfe_identify_hardware(bfe) == BFE_FAILURE) {
2891dd52495fSSaurabh Misra bfe_error(dip, "Could not identify device");
2892dd52495fSSaurabh Misra goto fail1;
2893dd52495fSSaurabh Misra }
2894dd52495fSSaurabh Misra
2895dd52495fSSaurabh Misra if (bfe_regs_map(bfe) != DDI_SUCCESS) {
2896dd52495fSSaurabh Misra bfe_error(dip, "Could not map device registers");
2897dd52495fSSaurabh Misra goto fail1;
2898dd52495fSSaurabh Misra }
2899dd52495fSSaurabh Misra
2900dd52495fSSaurabh Misra (void) bfe_get_chip_config(bfe);
2901dd52495fSSaurabh Misra
2902dd52495fSSaurabh Misra /*
2903dd52495fSSaurabh Misra * Register with MAC layer
2904dd52495fSSaurabh Misra */
2905dd52495fSSaurabh Misra if ((macreg = mac_alloc(MAC_VERSION)) == NULL) {
2906dd52495fSSaurabh Misra bfe_error(dip, "mac_alloc() failed");
2907dd52495fSSaurabh Misra goto fail2;
2908dd52495fSSaurabh Misra }
2909dd52495fSSaurabh Misra
2910dd52495fSSaurabh Misra macreg->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
2911dd52495fSSaurabh Misra macreg->m_driver = bfe;
2912dd52495fSSaurabh Misra macreg->m_dip = dip;
2913dd52495fSSaurabh Misra macreg->m_instance = unit;
2914dd52495fSSaurabh Misra macreg->m_src_addr = bfe->bfe_ether_addr;
2915dd52495fSSaurabh Misra macreg->m_callbacks = &bfe_mac_callbacks;
2916dd52495fSSaurabh Misra macreg->m_min_sdu = 0;
2917dd52495fSSaurabh Misra macreg->m_max_sdu = ETHERMTU;
2918dd52495fSSaurabh Misra macreg->m_margin = VLAN_TAGSZ;
2919dd52495fSSaurabh Misra
2920dd52495fSSaurabh Misra if ((ret = mac_register(macreg, &bfe->bfe_machdl)) != 0) {
2921dd52495fSSaurabh Misra bfe_error(dip, "mac_register() failed with %d error", ret);
2922dd52495fSSaurabh Misra mac_free(macreg);
2923dd52495fSSaurabh Misra goto fail2;
2924dd52495fSSaurabh Misra }
2925dd52495fSSaurabh Misra
2926dd52495fSSaurabh Misra mac_free(macreg);
2927dd52495fSSaurabh Misra
2928dd52495fSSaurabh Misra rw_init(&bfe->bfe_rwlock, NULL, RW_DRIVER,
2929dd52495fSSaurabh Misra DDI_INTR_PRI(bfe->bfe_intrpri));
2930dd52495fSSaurabh Misra
2931dd52495fSSaurabh Misra if (bfe_add_intr(bfe) != DDI_SUCCESS) {
2932dd52495fSSaurabh Misra bfe_error(dip, "Could not add interrupt");
2933dd52495fSSaurabh Misra goto fail3;
2934dd52495fSSaurabh Misra }
2935dd52495fSSaurabh Misra
2936dd52495fSSaurabh Misra if (bfe_rings_alloc(bfe) != DDI_SUCCESS) {
2937dd52495fSSaurabh Misra bfe_error(dip, "Could not allocate TX/RX Ring");
2938dd52495fSSaurabh Misra goto fail4;
2939dd52495fSSaurabh Misra }
2940dd52495fSSaurabh Misra
2941dd52495fSSaurabh Misra /* Init and then reset the chip */
2942dd52495fSSaurabh Misra bfe->bfe_chip_action = 0;
2943dd52495fSSaurabh Misra bfe_init_vars(bfe);
2944dd52495fSSaurabh Misra
2945dd52495fSSaurabh Misra /* PHY will also start running */
2946dd52495fSSaurabh Misra bfe_chip_reset(bfe);
2947dd52495fSSaurabh Misra
2948dd52495fSSaurabh Misra /*
2949dd52495fSSaurabh Misra * Even though we enable the interrupts here but chip's interrupt
2950dd52495fSSaurabh Misra * is not enabled yet. It will be enabled once we plumb the interface.
2951dd52495fSSaurabh Misra */
2952dd52495fSSaurabh Misra if (ddi_intr_enable(bfe->bfe_intrhdl) != DDI_SUCCESS) {
2953dd52495fSSaurabh Misra bfe_error(dip, "Could not enable interrupt");
2954dd52495fSSaurabh Misra goto fail4;
2955dd52495fSSaurabh Misra }
2956dd52495fSSaurabh Misra
2957dd52495fSSaurabh Misra return (DDI_SUCCESS);
2958dd52495fSSaurabh Misra
2959dd52495fSSaurabh Misra fail4:
2960dd52495fSSaurabh Misra bfe_remove_intr(bfe);
2961dd52495fSSaurabh Misra fail3:
2962c1374a13SSurya Prakki (void) mac_unregister(bfe->bfe_machdl);
2963dd52495fSSaurabh Misra fail2:
2964dd52495fSSaurabh Misra bfe_unmap_regs(bfe);
2965dd52495fSSaurabh Misra fail1:
2966dd52495fSSaurabh Misra pci_config_teardown(&bfe->bfe_conf_handle);
2967dd52495fSSaurabh Misra fail0:
2968dd52495fSSaurabh Misra kmem_free(bfe, sizeof (bfe_t));
2969dd52495fSSaurabh Misra return (DDI_FAILURE);
2970dd52495fSSaurabh Misra }
2971dd52495fSSaurabh Misra
2972dd52495fSSaurabh Misra static int
bfe_detach(dev_info_t * devinfo,ddi_detach_cmd_t cmd)2973dd52495fSSaurabh Misra bfe_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd)
2974dd52495fSSaurabh Misra {
2975dd52495fSSaurabh Misra bfe_t *bfe;
2976dd52495fSSaurabh Misra
2977dd52495fSSaurabh Misra bfe = ddi_get_driver_private(devinfo);
2978dd52495fSSaurabh Misra
2979dd52495fSSaurabh Misra switch (cmd) {
2980dd52495fSSaurabh Misra case DDI_DETACH:
2981dd52495fSSaurabh Misra /*
2982dd52495fSSaurabh Misra * We need to stop the timer before grabbing locks otherwise
2983dd52495fSSaurabh Misra * we can land-up in deadlock with untimeout.
2984dd52495fSSaurabh Misra */
2985dd52495fSSaurabh Misra bfe_stop_timer(bfe);
2986dd52495fSSaurabh Misra
2987dd52495fSSaurabh Misra /*
2988dd52495fSSaurabh Misra * First unregister with MAC layer before stopping DMA
2989dd52495fSSaurabh Misra * engine.
2990dd52495fSSaurabh Misra */
2991dd52495fSSaurabh Misra if (mac_unregister(bfe->bfe_machdl) != DDI_SUCCESS)
2992dd52495fSSaurabh Misra return (DDI_FAILURE);
2993dd52495fSSaurabh Misra
2994dd52495fSSaurabh Misra bfe->bfe_machdl = NULL;
2995dd52495fSSaurabh Misra
2996dd52495fSSaurabh Misra /*
2997dd52495fSSaurabh Misra * Quiesce the chip first.
2998dd52495fSSaurabh Misra */
2999dd52495fSSaurabh Misra bfe_grab_locks(bfe);
3000dd52495fSSaurabh Misra bfe_chip_halt(bfe);
3001dd52495fSSaurabh Misra bfe_stop_phy(bfe);
3002dd52495fSSaurabh Misra bfe_release_locks(bfe);
3003dd52495fSSaurabh Misra
3004dd52495fSSaurabh Misra (void) ddi_intr_disable(bfe->bfe_intrhdl);
3005dd52495fSSaurabh Misra
3006dd52495fSSaurabh Misra /* Make sure timer is gone. */
3007dd52495fSSaurabh Misra bfe_stop_timer(bfe);
3008dd52495fSSaurabh Misra
3009dd52495fSSaurabh Misra /*
3010dd52495fSSaurabh Misra * Free the DMA resources for buffer and then descriptors
3011dd52495fSSaurabh Misra */
3012dd52495fSSaurabh Misra if (bfe->bfe_tx_ring.r_flags == BFE_RING_ALLOCATED) {
3013dd52495fSSaurabh Misra /* TX */
3014dd52495fSSaurabh Misra bfe_buffer_free(&bfe->bfe_tx_ring);
3015dd52495fSSaurabh Misra bfe_ring_desc_free(&bfe->bfe_tx_ring);
3016dd52495fSSaurabh Misra }
3017dd52495fSSaurabh Misra
3018dd52495fSSaurabh Misra if (bfe->bfe_rx_ring.r_flags == BFE_RING_ALLOCATED) {
3019dd52495fSSaurabh Misra /* RX */
3020dd52495fSSaurabh Misra bfe_buffer_free(&bfe->bfe_rx_ring);
3021dd52495fSSaurabh Misra bfe_ring_desc_free(&bfe->bfe_rx_ring);
3022dd52495fSSaurabh Misra }
3023dd52495fSSaurabh Misra
3024dd52495fSSaurabh Misra bfe_remove_intr(bfe);
3025dd52495fSSaurabh Misra bfe_unmap_regs(bfe);
3026dd52495fSSaurabh Misra pci_config_teardown(&bfe->bfe_conf_handle);
3027dd52495fSSaurabh Misra
3028dd52495fSSaurabh Misra mutex_destroy(&bfe->bfe_tx_ring.r_lock);
3029dd52495fSSaurabh Misra mutex_destroy(&bfe->bfe_rx_ring.r_lock);
3030dd52495fSSaurabh Misra rw_destroy(&bfe->bfe_rwlock);
3031dd52495fSSaurabh Misra
3032dd52495fSSaurabh Misra kmem_free(bfe, sizeof (bfe_t));
3033dd52495fSSaurabh Misra
3034dd52495fSSaurabh Misra ddi_set_driver_private(devinfo, NULL);
3035dd52495fSSaurabh Misra return (DDI_SUCCESS);
3036dd52495fSSaurabh Misra
3037dd52495fSSaurabh Misra case DDI_SUSPEND:
3038dd52495fSSaurabh Misra /*
3039dd52495fSSaurabh Misra * We need to stop the timer before grabbing locks otherwise
3040dd52495fSSaurabh Misra * we can land-up in deadlock with untimeout.
3041dd52495fSSaurabh Misra */
3042dd52495fSSaurabh Misra bfe_stop_timer(bfe);
3043dd52495fSSaurabh Misra
3044dd52495fSSaurabh Misra /*
3045dd52495fSSaurabh Misra * Grab all the locks first.
3046dd52495fSSaurabh Misra */
3047dd52495fSSaurabh Misra bfe_grab_locks(bfe);
3048dd52495fSSaurabh Misra bfe_chip_halt(bfe);
3049dd52495fSSaurabh Misra bfe_stop_phy(bfe);
3050dd52495fSSaurabh Misra bfe->bfe_chip_state = BFE_CHIP_SUSPENDED;
3051dd52495fSSaurabh Misra bfe_release_locks(bfe);
3052dd52495fSSaurabh Misra
3053dd52495fSSaurabh Misra return (DDI_SUCCESS);
3054dd52495fSSaurabh Misra
3055dd52495fSSaurabh Misra default:
3056dd52495fSSaurabh Misra return (DDI_FAILURE);
3057dd52495fSSaurabh Misra }
3058dd52495fSSaurabh Misra }
3059dd52495fSSaurabh Misra
3060dd52495fSSaurabh Misra /*
3061dd52495fSSaurabh Misra * Quiesce the card for fast reboot
3062dd52495fSSaurabh Misra */
3063dd52495fSSaurabh Misra int
bfe_quiesce(dev_info_t * dev_info)3064dd52495fSSaurabh Misra bfe_quiesce(dev_info_t *dev_info)
3065dd52495fSSaurabh Misra {
3066dd52495fSSaurabh Misra bfe_t *bfe;
3067dd52495fSSaurabh Misra
3068dd52495fSSaurabh Misra bfe = ddi_get_driver_private(dev_info);
3069dd52495fSSaurabh Misra
3070dd52495fSSaurabh Misra bfe_chip_halt(bfe);
3071dd52495fSSaurabh Misra bfe_stop_phy(bfe);
3072dd52495fSSaurabh Misra bfe->bfe_chip_state = BFE_CHIP_QUIESCED;
3073dd52495fSSaurabh Misra
3074dd52495fSSaurabh Misra return (DDI_SUCCESS);
3075dd52495fSSaurabh Misra }
3076dd52495fSSaurabh Misra
3077dd52495fSSaurabh Misra static struct cb_ops bfe_cb_ops = {
3078dd52495fSSaurabh Misra nulldev, /* cb_open */
3079dd52495fSSaurabh Misra nulldev, /* cb_close */
3080dd52495fSSaurabh Misra nodev, /* cb_strategy */
3081dd52495fSSaurabh Misra nodev, /* cb_print */
3082dd52495fSSaurabh Misra nodev, /* cb_dump */
3083dd52495fSSaurabh Misra nodev, /* cb_read */
3084dd52495fSSaurabh Misra nodev, /* cb_write */
3085dd52495fSSaurabh Misra nodev, /* cb_ioctl */
3086dd52495fSSaurabh Misra nodev, /* cb_devmap */
3087dd52495fSSaurabh Misra nodev, /* cb_mmap */
3088dd52495fSSaurabh Misra nodev, /* cb_segmap */
3089dd52495fSSaurabh Misra nochpoll, /* cb_chpoll */
3090dd52495fSSaurabh Misra ddi_prop_op, /* cb_prop_op */
3091dd52495fSSaurabh Misra NULL, /* cb_stream */
3092dd52495fSSaurabh Misra D_MP | D_HOTPLUG, /* cb_flag */
3093dd52495fSSaurabh Misra CB_REV, /* cb_rev */
3094dd52495fSSaurabh Misra nodev, /* cb_aread */
3095dd52495fSSaurabh Misra nodev /* cb_awrite */
3096dd52495fSSaurabh Misra };
3097dd52495fSSaurabh Misra
3098dd52495fSSaurabh Misra static struct dev_ops bfe_dev_ops = {
3099dd52495fSSaurabh Misra DEVO_REV, /* devo_rev */
3100dd52495fSSaurabh Misra 0, /* devo_refcnt */
3101dd52495fSSaurabh Misra NULL, /* devo_getinfo */
3102dd52495fSSaurabh Misra nulldev, /* devo_identify */
3103dd52495fSSaurabh Misra nulldev, /* devo_probe */
3104dd52495fSSaurabh Misra bfe_attach, /* devo_attach */
3105dd52495fSSaurabh Misra bfe_detach, /* devo_detach */
3106dd52495fSSaurabh Misra nodev, /* devo_reset */
3107dd52495fSSaurabh Misra &bfe_cb_ops, /* devo_cb_ops */
3108dd52495fSSaurabh Misra NULL, /* devo_bus_ops */
3109dd52495fSSaurabh Misra ddi_power, /* devo_power */
3110dd52495fSSaurabh Misra bfe_quiesce /* devo_quiesce */
3111dd52495fSSaurabh Misra };
3112dd52495fSSaurabh Misra
3113dd52495fSSaurabh Misra static struct modldrv bfe_modldrv = {
3114dd52495fSSaurabh Misra &mod_driverops,
3115dd52495fSSaurabh Misra bfe_ident,
3116dd52495fSSaurabh Misra &bfe_dev_ops
3117dd52495fSSaurabh Misra };
3118dd52495fSSaurabh Misra
3119dd52495fSSaurabh Misra static struct modlinkage modlinkage = {
3120dd52495fSSaurabh Misra MODREV_1, (void *)&bfe_modldrv, NULL
3121dd52495fSSaurabh Misra };
3122dd52495fSSaurabh Misra
3123dd52495fSSaurabh Misra int
_info(struct modinfo * modinfop)3124dd52495fSSaurabh Misra _info(struct modinfo *modinfop)
3125dd52495fSSaurabh Misra {
3126dd52495fSSaurabh Misra return (mod_info(&modlinkage, modinfop));
3127dd52495fSSaurabh Misra }
3128dd52495fSSaurabh Misra
3129dd52495fSSaurabh Misra int
_init(void)3130dd52495fSSaurabh Misra _init(void)
3131dd52495fSSaurabh Misra {
3132dd52495fSSaurabh Misra int status;
3133dd52495fSSaurabh Misra
3134dd52495fSSaurabh Misra mac_init_ops(&bfe_dev_ops, MODULE_NAME);
3135dd52495fSSaurabh Misra status = mod_install(&modlinkage);
3136dd52495fSSaurabh Misra if (status == DDI_FAILURE)
3137dd52495fSSaurabh Misra mac_fini_ops(&bfe_dev_ops);
3138dd52495fSSaurabh Misra return (status);
3139dd52495fSSaurabh Misra }
3140dd52495fSSaurabh Misra
3141dd52495fSSaurabh Misra int
_fini(void)3142dd52495fSSaurabh Misra _fini(void)
3143dd52495fSSaurabh Misra {
3144dd52495fSSaurabh Misra int status;
3145dd52495fSSaurabh Misra
3146dd52495fSSaurabh Misra status = mod_remove(&modlinkage);
3147dd52495fSSaurabh Misra if (status == 0) {
3148dd52495fSSaurabh Misra mac_fini_ops(&bfe_dev_ops);
3149dd52495fSSaurabh Misra }
3150dd52495fSSaurabh Misra return (status);
3151dd52495fSSaurabh Misra }
3152