1d39a76e7Sxw /*
2d39a76e7Sxw * CDDL HEADER START
3d39a76e7Sxw *
4d39a76e7Sxw * The contents of this file are subject to the terms of the
5d39a76e7Sxw * Common Development and Distribution License (the "License").
6d39a76e7Sxw * You may not use this file except in compliance with the License.
7d39a76e7Sxw *
8d39a76e7Sxw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9d39a76e7Sxw * or http://www.opensolaris.org/os/licensing.
10d39a76e7Sxw * See the License for the specific language governing permissions
11d39a76e7Sxw * and limitations under the License.
12d39a76e7Sxw *
13d39a76e7Sxw * When distributing Covered Code, include this CDDL HEADER in each
14d39a76e7Sxw * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15d39a76e7Sxw * If applicable, add the following below this CDDL HEADER, with the
16d39a76e7Sxw * fields enclosed by brackets "[]" replaced with your own identifying
17d39a76e7Sxw * information: Portions Copyright [yyyy] [name of copyright owner]
18d39a76e7Sxw *
19d39a76e7Sxw * CDDL HEADER END
20d39a76e7Sxw */
21d39a76e7Sxw
22d39a76e7Sxw /*
23d39a76e7Sxw * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24d39a76e7Sxw * Use is subject to license terms.
25d39a76e7Sxw */
26d39a76e7Sxw
27d39a76e7Sxw /*
28d39a76e7Sxw * This file is part of the Chelsio T1 Ethernet driver.
29d39a76e7Sxw *
30d39a76e7Sxw * Copyright (C) 2003-2005 Chelsio Communications. All rights reserved.
31d39a76e7Sxw */
32d39a76e7Sxw
33d39a76e7Sxw /*
34d39a76e7Sxw * Solaris Multithreaded STREAMS Chelsio PCI Ethernet Driver.
35d39a76e7Sxw * Interface code
36d39a76e7Sxw */
37d39a76e7Sxw
38d39a76e7Sxw #include <sys/types.h>
39d39a76e7Sxw #include <sys/systm.h>
40d39a76e7Sxw #include <sys/cmn_err.h>
41d39a76e7Sxw #include <sys/ddi.h>
42d39a76e7Sxw #include <sys/sunddi.h>
43d39a76e7Sxw #include <sys/byteorder.h>
44d39a76e7Sxw #include <sys/atomic.h>
45d39a76e7Sxw #include <sys/ethernet.h>
46d39a76e7Sxw #if PE_PROFILING_ENABLED
47d39a76e7Sxw #include <sys/time.h>
48d39a76e7Sxw #endif
49d39a76e7Sxw #include <sys/gld.h>
50d39a76e7Sxw #include "ostypes.h"
51d39a76e7Sxw #include "common.h"
52d39a76e7Sxw #include "oschtoe.h"
53d39a76e7Sxw #ifdef CONFIG_CHELSIO_T1_1G
54d39a76e7Sxw #include "fpga_defs.h"
55d39a76e7Sxw #endif
56d39a76e7Sxw #include "regs.h"
57d39a76e7Sxw #ifdef CONFIG_CHELSIO_T1_OFFLOAD
58d39a76e7Sxw #include "mc3.h"
59d39a76e7Sxw #include "mc4.h"
60d39a76e7Sxw #endif
61d39a76e7Sxw #include "sge.h"
62d39a76e7Sxw #include "tp.h"
63d39a76e7Sxw #ifdef CONFIG_CHELSIO_T1_OFFLOAD
64d39a76e7Sxw #include "ulp.h"
65d39a76e7Sxw #endif
66d39a76e7Sxw #include "espi.h"
67d39a76e7Sxw #include "elmer0.h"
68d39a76e7Sxw #include "gmac.h"
69d39a76e7Sxw #include "cphy.h"
70d39a76e7Sxw #include "suni1x10gexp_regs.h"
71d39a76e7Sxw #include "ch.h"
72d39a76e7Sxw
73d39a76e7Sxw #define MLEN(mp) ((mp)->b_wptr - (mp)->b_rptr)
74d39a76e7Sxw
75d39a76e7Sxw extern uint32_t buffers_in_use[];
76d39a76e7Sxw extern kmutex_t in_use_l;
77d39a76e7Sxw extern uint32_t in_use_index;
78d39a76e7Sxw
79d39a76e7Sxw static void link_start(ch_t *sa, struct pe_port_t *pp);
80d39a76e7Sxw static ch_esb_t *ch_alloc_small_esbbuf(ch_t *sa, uint32_t i);
81d39a76e7Sxw static ch_esb_t *ch_alloc_big_esbbuf(ch_t *sa, uint32_t i);
82d39a76e7Sxw void ch_big_rbuf_recycle(ch_esb_t *rbp);
83d39a76e7Sxw void ch_small_rbuf_recycle(ch_esb_t *rbp);
84d39a76e7Sxw static const struct board_info *pe_sa_init(ch_t *sa);
85d39a76e7Sxw static int ch_set_config_data(ch_t *chp);
86d39a76e7Sxw void pe_rbuf_pool_free(ch_t *chp);
87d39a76e7Sxw static void pe_free_driver_resources(ch_t *sa);
88d39a76e7Sxw static void update_mtu_tab(ch_t *adapter);
89d39a76e7Sxw static int pe_change_mtu(ch_t *chp);
90d39a76e7Sxw
91d39a76e7Sxw /*
92d39a76e7Sxw * CPL5 Defines (from netinet/cpl5_commands.h)
93d39a76e7Sxw */
94d39a76e7Sxw #define FLITSTOBYTES 8
95d39a76e7Sxw
96d39a76e7Sxw #define CPL_FORMAT_0_SIZE 8
97d39a76e7Sxw #define CPL_FORMAT_1_SIZE 16
98d39a76e7Sxw #define CPL_FORMAT_2_SIZE 24
99d39a76e7Sxw #define CPL_FORMAT_3_SIZE 32
100d39a76e7Sxw #define CPL_FORMAT_4_SIZE 40
101d39a76e7Sxw #define CPL_FORMAT_5_SIZE 48
102d39a76e7Sxw
103d39a76e7Sxw #define TID_MASK 0xffffff
104d39a76e7Sxw
105d39a76e7Sxw #define PE_LINK_SPEED_AUTONEG 5
106d39a76e7Sxw
107d39a76e7Sxw static int pe_small_rbuf_pool_init(ch_t *sa);
108d39a76e7Sxw static int pe_big_rbuf_pool_init(ch_t *sa);
109d39a76e7Sxw static int pe_make_fake_arp(ch_t *chp, unsigned char *arpp);
110d39a76e7Sxw static uint32_t pe_get_ip(unsigned char *arpp);
111d39a76e7Sxw
112d39a76e7Sxw /*
113d39a76e7Sxw * May be set in /etc/system to 0 to use default latency timer for 10G.
114d39a76e7Sxw * See PCI register 0xc definition.
115d39a76e7Sxw */
116d39a76e7Sxw int enable_latency_timer = 1;
117d39a76e7Sxw
118d39a76e7Sxw /*
119d39a76e7Sxw * May be set in /etc/system to 0 to disable hardware checksum for
120d39a76e7Sxw * TCP and UDP.
121d39a76e7Sxw */
122d39a76e7Sxw int enable_checksum_offload = 1;
123d39a76e7Sxw
124d39a76e7Sxw /*
125d39a76e7Sxw * Multiplier for freelist pool.
126d39a76e7Sxw */
127d39a76e7Sxw int fl_sz_multiplier = 6;
128d39a76e7Sxw
129d39a76e7Sxw uint_t
pe_intr(ch_t * sa)130d39a76e7Sxw pe_intr(ch_t *sa)
131d39a76e7Sxw {
132d39a76e7Sxw mutex_enter(&sa->ch_intr);
133d39a76e7Sxw
134d39a76e7Sxw if (sge_data_in(sa->sge)) {
135d39a76e7Sxw sa->isr_intr++;
136d39a76e7Sxw mutex_exit(&sa->ch_intr);
137d39a76e7Sxw return (DDI_INTR_CLAIMED);
138d39a76e7Sxw }
139d39a76e7Sxw
140d39a76e7Sxw mutex_exit(&sa->ch_intr);
141d39a76e7Sxw
142d39a76e7Sxw return (DDI_INTR_UNCLAIMED);
143d39a76e7Sxw }
144d39a76e7Sxw
145d39a76e7Sxw /*
146d39a76e7Sxw * Each setup struct will call this function to
147d39a76e7Sxw * initialize.
148d39a76e7Sxw */
149d39a76e7Sxw void
pe_init(void * xsa)150d39a76e7Sxw pe_init(void* xsa)
151d39a76e7Sxw {
152d39a76e7Sxw ch_t *sa = NULL;
153d39a76e7Sxw int i = 0;
154d39a76e7Sxw
155d39a76e7Sxw sa = (ch_t *)xsa;
156d39a76e7Sxw
157d39a76e7Sxw /*
158d39a76e7Sxw * Need to count the number of times this routine is called
159d39a76e7Sxw * because we only want the resources to be allocated once.
160d39a76e7Sxw * The 7500 has four ports and so this routine can be called
161d39a76e7Sxw * once for each port.
162d39a76e7Sxw */
163d39a76e7Sxw if (sa->init_counter == 0) {
164d39a76e7Sxw for_each_port(sa, i) {
165d39a76e7Sxw
166d39a76e7Sxw /*
167d39a76e7Sxw * We only want to initialize the line if it is down.
168d39a76e7Sxw */
169d39a76e7Sxw if (sa->port[i].line_up == 0) {
170d39a76e7Sxw link_start(sa, &sa->port[i]);
171d39a76e7Sxw sa->port[i].line_up = 1;
172d39a76e7Sxw }
173d39a76e7Sxw }
174d39a76e7Sxw
175d39a76e7Sxw (void) t1_init_hw_modules(sa);
176d39a76e7Sxw
177d39a76e7Sxw /*
178d39a76e7Sxw * Enable/Disable checksum offloading.
179d39a76e7Sxw */
180d39a76e7Sxw if (sa->ch_config.cksum_enabled) {
181d39a76e7Sxw if (sa->config_data.offload_ip_cksum) {
182d39a76e7Sxw /* Notify that HW will do the checksum. */
183d39a76e7Sxw t1_tp_set_ip_checksum_offload(sa->tp, 1);
184d39a76e7Sxw }
185d39a76e7Sxw
186d39a76e7Sxw if (sa->config_data.offload_tcp_cksum) {
187d39a76e7Sxw /* Notify that HW will do the checksum. */
188d39a76e7Sxw t1_tp_set_tcp_checksum_offload(sa->tp, 1);
189d39a76e7Sxw }
190d39a76e7Sxw
191d39a76e7Sxw if (sa->config_data.offload_udp_cksum) {
192d39a76e7Sxw /* Notify that HW will do the checksum. */
193d39a76e7Sxw t1_tp_set_udp_checksum_offload(sa->tp, 1);
194d39a76e7Sxw }
195d39a76e7Sxw }
196d39a76e7Sxw
197d39a76e7Sxw sa->ch_flags |= PEINITDONE;
198d39a76e7Sxw
199d39a76e7Sxw sa->init_counter++;
200d39a76e7Sxw }
201d39a76e7Sxw
202d39a76e7Sxw /*
203d39a76e7Sxw * Enable interrupts after starting the SGE so
204d39a76e7Sxw * that the SGE is ready to handle interrupts.
205d39a76e7Sxw */
206d39a76e7Sxw (void) sge_start(sa->sge);
207d39a76e7Sxw t1_interrupts_enable(sa);
208d39a76e7Sxw
209d39a76e7Sxw /*
210d39a76e7Sxw * set mtu (either 1500 or bigger)
211d39a76e7Sxw */
212d39a76e7Sxw (void) pe_change_mtu(sa);
213d39a76e7Sxw #ifdef HOST_PAUSE
214d39a76e7Sxw /*
215d39a76e7Sxw * get the configured value of the MAC.
216d39a76e7Sxw */
217d39a76e7Sxw (void) t1_tpi_read(sa, SUNI1x10GEXP_REG_TXXG_CONFIG_1 << 2,
218d39a76e7Sxw &sa->txxg_cfg1);
219d39a76e7Sxw #endif
220d39a76e7Sxw }
221d39a76e7Sxw
222d39a76e7Sxw /* ARGSUSED */
223d39a76e7Sxw static void
link_start(ch_t * sa,struct pe_port_t * p)224d39a76e7Sxw link_start(ch_t *sa, struct pe_port_t *p)
225d39a76e7Sxw {
226d39a76e7Sxw struct cmac *mac = p->mac;
227d39a76e7Sxw
228d39a76e7Sxw mac->ops->reset(mac);
229d39a76e7Sxw if (mac->ops->macaddress_set)
230d39a76e7Sxw mac->ops->macaddress_set(mac, p->enaddr);
231d39a76e7Sxw (void) t1_link_start(p->phy, mac, &p->link_config);
232d39a76e7Sxw mac->ops->enable(mac, MAC_DIRECTION_RX | MAC_DIRECTION_TX);
233d39a76e7Sxw }
234d39a76e7Sxw
235d39a76e7Sxw /*
236d39a76e7Sxw * turn off interrupts...
237d39a76e7Sxw */
238d39a76e7Sxw void
pe_stop(ch_t * sa)239d39a76e7Sxw pe_stop(ch_t *sa)
240d39a76e7Sxw {
241d39a76e7Sxw t1_interrupts_disable(sa);
242d39a76e7Sxw (void) sge_stop(sa->sge);
243d39a76e7Sxw
244d39a76e7Sxw /*
245d39a76e7Sxw * we can still be running an interrupt thread in sge_data_in().
246d39a76e7Sxw * If we are, we'll block on the ch_intr lock
247d39a76e7Sxw */
248d39a76e7Sxw mutex_enter(&sa->ch_intr);
249d39a76e7Sxw mutex_exit(&sa->ch_intr);
250d39a76e7Sxw }
251d39a76e7Sxw
252d39a76e7Sxw /*
253d39a76e7Sxw * output mblk to SGE level and out to the wire.
254d39a76e7Sxw */
255d39a76e7Sxw
256d39a76e7Sxw int
pe_start(ch_t * sa,mblk_t * mp,uint32_t flg)257d39a76e7Sxw pe_start(ch_t *sa, mblk_t *mp, uint32_t flg)
258d39a76e7Sxw {
259d39a76e7Sxw mblk_t *m0 = mp;
260d39a76e7Sxw cmdQ_ce_t cm[16];
261d39a76e7Sxw cmdQ_ce_t *cmp;
262d39a76e7Sxw cmdQ_ce_t *hmp = &cm[0]; /* head of cm table (may be kmem_alloed) */
263d39a76e7Sxw int cm_flg = 0; /* flag (1 - if kmem-alloced) */
264d39a76e7Sxw int nseg = 0; /* number cmdQ_ce entries created */
265d39a76e7Sxw int mseg = 16; /* maximum entries in hmp arrary */
266d39a76e7Sxw int freeme = 0; /* we have an mblk to free in case of error */
267d39a76e7Sxw uint32_t ch_bind_dma_handle(ch_t *, int, caddr_t, cmdQ_ce_t *,
268d39a76e7Sxw uint32_t);
269d39a76e7Sxw #if defined(__sparc)
270d39a76e7Sxw uint32_t ch_bind_dvma_handle(ch_t *, int, caddr_t, cmdQ_ce_t *,
271d39a76e7Sxw uint32_t);
272d39a76e7Sxw #endif
273d39a76e7Sxw int rv; /* return value on error */
274d39a76e7Sxw
275d39a76e7Sxw #ifdef CONFIG_CHELSIO_T1_OFFLOAD
276d39a76e7Sxw if (flg & CH_OFFLOAD) {
277d39a76e7Sxw hmp->ce_pa = ((tbuf_t *)mp)->tb_pa;
278d39a76e7Sxw hmp->ce_dh = NULL;
279d39a76e7Sxw hmp->ce_flg = DH_TOE;
280d39a76e7Sxw hmp->ce_len = ((tbuf_t *)mp)->tb_len;
281d39a76e7Sxw hmp->ce_mp = mp;
282d39a76e7Sxw
283d39a76e7Sxw /* make sure data is flushed to physical memory */
284d39a76e7Sxw (void) ddi_dma_sync((ddi_dma_handle_t)((tbuf_t *)mp)->tb_dh,
285d39a76e7Sxw (off_t)0, hmp->ce_len, DDI_DMA_SYNC_FORDEV);
286d39a76e7Sxw
287d39a76e7Sxw if (sge_data_out(sa->sge, 0, mp, hmp, 1, flg) == 0) {
288d39a76e7Sxw return (0);
289d39a76e7Sxw }
290d39a76e7Sxw
291d39a76e7Sxw /*
292d39a76e7Sxw * set a flag so we'll restart upper layer when
293d39a76e7Sxw * resources become available.
294d39a76e7Sxw */
295d39a76e7Sxw sa->ch_blked = 1;
296d39a76e7Sxw return (1);
297d39a76e7Sxw }
298d39a76e7Sxw #endif /* CONFIG_CHELSIO_T1_OFFLOAD */
299d39a76e7Sxw
300d39a76e7Sxw /* writes from toe will always have CPL header in place */
301d39a76e7Sxw if (flg & CH_NO_CPL) {
302d39a76e7Sxw struct cpl_tx_pkt *cpl;
303d39a76e7Sxw
304d39a76e7Sxw /* PR2928 & PR3309 */
30511abda1eSToomas Soome if (sa->ch_ip == 0) {
306d39a76e7Sxw ushort_t ethertype = ntohs(*(short *)&mp->b_rptr[12]);
307d39a76e7Sxw if (ethertype == ETHERTYPE_ARP) {
308d39a76e7Sxw if (is_T2(sa)) {
309d39a76e7Sxw /*
310d39a76e7Sxw * We assume here that the arp will be
311d39a76e7Sxw * contained in one mblk.
312d39a76e7Sxw */
313d39a76e7Sxw if (pe_make_fake_arp(sa, mp->b_rptr)) {
314d39a76e7Sxw freemsg(mp);
315d39a76e7Sxw sa->oerr++;
316d39a76e7Sxw return (0);
317d39a76e7Sxw }
318d39a76e7Sxw } else {
319d39a76e7Sxw sa->ch_ip = pe_get_ip(mp->b_rptr);
320d39a76e7Sxw }
321d39a76e7Sxw }
322d39a76e7Sxw }
323d39a76e7Sxw
324d39a76e7Sxw /*
325d39a76e7Sxw * if space in front of packet big enough for CPL
326d39a76e7Sxw * header, then use it. We'll allocate an mblk
327d39a76e7Sxw * otherwise.
328d39a76e7Sxw */
329d39a76e7Sxw if ((mp->b_rptr - mp->b_datap->db_base) >= SZ_CPL_TX_PKT) {
330d39a76e7Sxw
331d39a76e7Sxw mp->b_rptr -= SZ_CPL_TX_PKT;
332d39a76e7Sxw
333d39a76e7Sxw } else {
334d39a76e7Sxw
335d39a76e7Sxw #ifdef SUN_KSTATS
336d39a76e7Sxw sa->sge->intr_cnt.tx_need_cpl_space++;
337d39a76e7Sxw #endif
338d39a76e7Sxw m0 = allocb(SZ_CPL_TX_PKT, BPRI_HI);
339d39a76e7Sxw if (m0 == NULL) {
340d39a76e7Sxw freemsg(mp);
341d39a76e7Sxw sa->oerr++;
342d39a76e7Sxw return (0);
343d39a76e7Sxw }
344d39a76e7Sxw
345d39a76e7Sxw m0->b_wptr = m0->b_rptr + SZ_CPL_TX_PKT;
346d39a76e7Sxw m0->b_cont = mp;
347d39a76e7Sxw freeme = 1;
348d39a76e7Sxw
349d39a76e7Sxw mp = m0;
350d39a76e7Sxw }
351d39a76e7Sxw
352d39a76e7Sxw /* fill in cpl header */
353d39a76e7Sxw cpl = (struct cpl_tx_pkt *)mp->b_rptr;
354d39a76e7Sxw cpl->opcode = CPL_TX_PKT;
355d39a76e7Sxw cpl->iff = 0; /* XXX port 0 needs fixing with NEMO */
356d39a76e7Sxw cpl->ip_csum_dis = 1; /* no IP header cksum */
357d39a76e7Sxw cpl->l4_csum_dis =
358d39a76e7Sxw flg & CH_NO_HWCKSUM; /* CH_NO_HWCKSUM == 1 */
359d39a76e7Sxw cpl->vlan_valid = 0; /* no vlan */
360d39a76e7Sxw }
361d39a76e7Sxw
362d39a76e7Sxw if (m0->b_cont) {
363d39a76e7Sxw
364d39a76e7Sxw #ifdef SUN_KSTATS
365d39a76e7Sxw sa->sge->intr_cnt.tx_multi_mblks++;
366d39a76e7Sxw #endif
367d39a76e7Sxw
368d39a76e7Sxw while (mp) {
369d39a76e7Sxw int lseg; /* added by ch_bind_dma_handle() */
370d39a76e7Sxw int len;
371d39a76e7Sxw
372d39a76e7Sxw len = MLEN(mp);
373d39a76e7Sxw /* skip mlks with no data */
374d39a76e7Sxw if (len == 0) {
375d39a76e7Sxw mp = mp->b_cont;
376d39a76e7Sxw continue;
377d39a76e7Sxw }
378d39a76e7Sxw
379d39a76e7Sxw /*
380d39a76e7Sxw * if we've run out of space on stack, then we
381d39a76e7Sxw * allocate a temporary buffer to hold the
382d39a76e7Sxw * information. This will kill the the performance,
383d39a76e7Sxw * but since it shouldn't really occur, we can live
384d39a76e7Sxw * with it. Since jumbo frames may map multiple
385d39a76e7Sxw * descriptors, we reallocate the hmp[] array before
386d39a76e7Sxw * we reach the end.
387d39a76e7Sxw */
388d39a76e7Sxw if (nseg >= (mseg-4)) {
389d39a76e7Sxw cmdQ_ce_t *buf;
390d39a76e7Sxw int j;
391d39a76e7Sxw
392d39a76e7Sxw buf = kmem_alloc(sizeof (cmdQ_ce_t) * 2 * mseg,
393d39a76e7Sxw KM_SLEEP);
394d39a76e7Sxw
395d39a76e7Sxw for (j = 0; j < nseg; j++)
396d39a76e7Sxw buf[j] = hmp[j];
397d39a76e7Sxw
398d39a76e7Sxw if (cm_flg) {
399d39a76e7Sxw kmem_free(hmp,
400d39a76e7Sxw mseg * sizeof (cmdQ_ce_t));
401d39a76e7Sxw } else
402d39a76e7Sxw cm_flg = 1;
403d39a76e7Sxw
404d39a76e7Sxw hmp = buf;
405d39a76e7Sxw mseg = 2*mseg;
406d39a76e7Sxw
407d39a76e7Sxw /*
408d39a76e7Sxw * We've used up ch table on stack
409d39a76e7Sxw */
410d39a76e7Sxw }
411d39a76e7Sxw
412d39a76e7Sxw #if defined(__sparc)
413d39a76e7Sxw if (sa->ch_config.enable_dvma) {
414d39a76e7Sxw lseg = ch_bind_dvma_handle(sa, len,
415d39a76e7Sxw (void *)mp->b_rptr,
416d39a76e7Sxw &hmp[nseg], mseg - nseg);
417*4e2c3273SToomas Soome if (lseg == 0) {
418d39a76e7Sxw sa->sge->intr_cnt.tx_no_dvma1++;
419d39a76e7Sxw if ((lseg = ch_bind_dma_handle(sa, len,
420d39a76e7Sxw (void *)mp->b_rptr,
421d39a76e7Sxw &hmp[nseg],
422*4e2c3273SToomas Soome mseg - nseg)) == 0) {
423d39a76e7Sxw sa->sge->intr_cnt.tx_no_dma1++;
424d39a76e7Sxw
425d39a76e7Sxw /*
426d39a76e7Sxw * ran out of space. Gonna bale
427d39a76e7Sxw */
428d39a76e7Sxw rv = 0;
429d39a76e7Sxw
430d39a76e7Sxw /*
431d39a76e7Sxw * we may have processed
432d39a76e7Sxw * previous mblks and have
433d39a76e7Sxw * descriptors. If so, we need
434d39a76e7Sxw * to free the meta struct
435d39a76e7Sxw * entries before freeing
436d39a76e7Sxw * the mblk.
437d39a76e7Sxw */
438d39a76e7Sxw if (nseg)
439d39a76e7Sxw goto error;
440d39a76e7Sxw goto error1;
441d39a76e7Sxw }
442d39a76e7Sxw }
443d39a76e7Sxw } else {
444d39a76e7Sxw lseg = ch_bind_dma_handle(sa, len,
445d39a76e7Sxw (void *)mp->b_rptr, &hmp[nseg],
446d39a76e7Sxw mseg - nseg);
447*4e2c3273SToomas Soome if (lseg == 0) {
448d39a76e7Sxw sa->sge->intr_cnt.tx_no_dma1++;
449d39a76e7Sxw
450d39a76e7Sxw /*
451d39a76e7Sxw * ran out of space. Gona bale
452d39a76e7Sxw */
453d39a76e7Sxw rv = 0;
454d39a76e7Sxw
455d39a76e7Sxw /*
456d39a76e7Sxw * we may have processed previous
457d39a76e7Sxw * mblks and have descriptors. If so,
458d39a76e7Sxw * we need to free the meta struct
459d39a76e7Sxw * entries before freeing the mblk.
460d39a76e7Sxw */
461d39a76e7Sxw if (nseg)
462d39a76e7Sxw goto error;
463d39a76e7Sxw goto error1;
464d39a76e7Sxw }
465d39a76e7Sxw }
466d39a76e7Sxw #else /* defined(__sparc) */
467d39a76e7Sxw lseg = ch_bind_dma_handle(sa, len,
468d39a76e7Sxw (void *)mp->b_rptr, &hmp[nseg],
469d39a76e7Sxw mseg - nseg);
47011abda1eSToomas Soome if (lseg == 0) {
471d39a76e7Sxw sa->sge->intr_cnt.tx_no_dma1++;
472d39a76e7Sxw
473d39a76e7Sxw /*
474d39a76e7Sxw * ran out of space. Gona bale
475d39a76e7Sxw */
476d39a76e7Sxw rv = 0;
477d39a76e7Sxw
478d39a76e7Sxw /*
479d39a76e7Sxw * we may have processed previous mblks and
480d39a76e7Sxw * have descriptors. If so, we need to free
481d39a76e7Sxw * the meta struct entries before freeing
482d39a76e7Sxw * the mblk.
483d39a76e7Sxw */
484d39a76e7Sxw if (nseg)
485d39a76e7Sxw goto error;
486d39a76e7Sxw goto error1;
487d39a76e7Sxw }
488d39a76e7Sxw #endif /* defined(__sparc) */
489d39a76e7Sxw nseg += lseg;
490d39a76e7Sxw mp = mp->b_cont;
491d39a76e7Sxw }
492d39a76e7Sxw
493d39a76e7Sxw /*
494d39a76e7Sxw * SHOULD NEVER OCCUR, BUT...
495d39a76e7Sxw * no data if nseg 0 or
496d39a76e7Sxw * nseg 1 and a CPL mblk (CPL mblk only with offload mode)
497d39a76e7Sxw * and no data
498d39a76e7Sxw */
499d39a76e7Sxw if ((nseg == 0) || (freeme && (nseg == 1))) {
500d39a76e7Sxw rv = 0;
501d39a76e7Sxw goto error1;
502d39a76e7Sxw }
503d39a76e7Sxw
504d39a76e7Sxw } else {
505d39a76e7Sxw int len;
506d39a76e7Sxw
507d39a76e7Sxw /* we assume that we always have data with one packet */
508d39a76e7Sxw len = MLEN(mp);
509d39a76e7Sxw
510d39a76e7Sxw #if defined(__sparc)
511d39a76e7Sxw if (sa->ch_config.enable_dvma) {
512d39a76e7Sxw nseg = ch_bind_dvma_handle(sa, len,
513d39a76e7Sxw (void *)mp->b_rptr,
514d39a76e7Sxw &hmp[0], 16);
515*4e2c3273SToomas Soome if (nseg == 0) {
516d39a76e7Sxw sa->sge->intr_cnt.tx_no_dvma2++;
517d39a76e7Sxw nseg = ch_bind_dma_handle(sa, len,
518d39a76e7Sxw (void *)mp->b_rptr,
519d39a76e7Sxw &hmp[0], 16);
520*4e2c3273SToomas Soome if (nseg == 0) {
521d39a76e7Sxw sa->sge->intr_cnt.tx_no_dma2++;
522d39a76e7Sxw
523d39a76e7Sxw /*
524d39a76e7Sxw * ran out of space. Gona bale
525d39a76e7Sxw */
526d39a76e7Sxw rv = 0;
527d39a76e7Sxw goto error1;
528d39a76e7Sxw }
529d39a76e7Sxw }
530d39a76e7Sxw } else {
531d39a76e7Sxw nseg = ch_bind_dma_handle(sa, len,
532d39a76e7Sxw (void *)mp->b_rptr, &hmp[0], 16);
533*4e2c3273SToomas Soome if (nseg == 0) {
534d39a76e7Sxw sa->sge->intr_cnt.tx_no_dma2++;
535d39a76e7Sxw
536d39a76e7Sxw /*
537d39a76e7Sxw * ran out of space. Gona bale
538d39a76e7Sxw */
539d39a76e7Sxw rv = 0;
540d39a76e7Sxw goto error1;
541d39a76e7Sxw }
542d39a76e7Sxw }
543d39a76e7Sxw #else /* defined(__sparc) */
544d39a76e7Sxw nseg = ch_bind_dma_handle(sa, len,
545d39a76e7Sxw (void *)mp->b_rptr, &hmp[0], 16);
54611abda1eSToomas Soome if (nseg == 0) {
547d39a76e7Sxw sa->sge->intr_cnt.tx_no_dma2++;
548d39a76e7Sxw
549d39a76e7Sxw /*
550d39a76e7Sxw * ran out of space. Gona bale
551d39a76e7Sxw */
552d39a76e7Sxw rv = 0;
553d39a76e7Sxw goto error1;
554d39a76e7Sxw }
555d39a76e7Sxw #endif /* defined(__sparc) */
556d39a76e7Sxw
557d39a76e7Sxw /*
558d39a76e7Sxw * dummy arp message to handle PR3309 & PR2928
559d39a76e7Sxw */
560d39a76e7Sxw if (flg & CH_ARP)
561d39a76e7Sxw hmp->ce_flg |= DH_ARP;
562d39a76e7Sxw }
563d39a76e7Sxw
564d39a76e7Sxw if (sge_data_out(sa->sge, 0, m0, hmp, nseg, flg) == 0) {
565d39a76e7Sxw if (cm_flg)
566d39a76e7Sxw kmem_free(hmp, mseg * sizeof (cmdQ_ce_t));
567d39a76e7Sxw return (0);
568d39a76e7Sxw }
569d39a76e7Sxw
570d39a76e7Sxw /*
571d39a76e7Sxw * set a flag so we'll restart upper layer when
572d39a76e7Sxw * resources become available.
573d39a76e7Sxw */
574d39a76e7Sxw if ((flg & CH_ARP) == 0)
575d39a76e7Sxw sa->ch_blked = 1;
576d39a76e7Sxw rv = 1;
577d39a76e7Sxw
578d39a76e7Sxw error:
579d39a76e7Sxw /*
580d39a76e7Sxw * unmap the physical addresses allocated earlier.
581d39a76e7Sxw */
582d39a76e7Sxw cmp = hmp;
583d39a76e7Sxw for (--nseg; nseg >= 0; nseg--) {
584d39a76e7Sxw if (cmp->ce_dh) {
585d39a76e7Sxw if (cmp->ce_flg == DH_DMA)
586d39a76e7Sxw ch_unbind_dma_handle(sa, cmp->ce_dh);
587d39a76e7Sxw #if defined(__sparc)
588d39a76e7Sxw else
589d39a76e7Sxw ch_unbind_dvma_handle(sa, cmp->ce_dh);
590d39a76e7Sxw #endif
591d39a76e7Sxw }
592d39a76e7Sxw cmp++;
593d39a76e7Sxw }
594d39a76e7Sxw
595d39a76e7Sxw error1:
596d39a76e7Sxw
597d39a76e7Sxw /* free the temporary array */
598d39a76e7Sxw if (cm_flg)
599d39a76e7Sxw kmem_free(hmp, mseg * sizeof (cmdQ_ce_t));
600d39a76e7Sxw
601d39a76e7Sxw /*
602d39a76e7Sxw * if we've allocated an mblk above, then we need to free it
603d39a76e7Sxw * before returning. This is safe since we haven't done anything to
604d39a76e7Sxw * the original message. The caller, gld, will still have a pointer
605d39a76e7Sxw * to the original mblk.
606d39a76e7Sxw */
607d39a76e7Sxw if (rv == 1) {
608d39a76e7Sxw if (freeme) {
609d39a76e7Sxw /* we had to allocate an mblk. Free it. */
610d39a76e7Sxw freeb(m0);
611d39a76e7Sxw } else {
612d39a76e7Sxw /* adjust the mblk back to original start */
613d39a76e7Sxw if (flg & CH_NO_CPL)
614d39a76e7Sxw m0->b_rptr += SZ_CPL_TX_PKT;
615d39a76e7Sxw }
616d39a76e7Sxw } else {
617d39a76e7Sxw freemsg(m0);
618d39a76e7Sxw sa->oerr++;
619d39a76e7Sxw }
620d39a76e7Sxw
621d39a76e7Sxw return (rv);
622d39a76e7Sxw }
623d39a76e7Sxw
624d39a76e7Sxw /* KLUDGE ALERT. HARD WIRED TO PORT ZERO */
625d39a76e7Sxw void
pe_set_mac(ch_t * sa,unsigned char * ac_enaddr)626d39a76e7Sxw pe_set_mac(ch_t *sa, unsigned char *ac_enaddr)
627d39a76e7Sxw {
628d39a76e7Sxw sa->port[0].mac->ops->macaddress_set(sa->port[0].mac, ac_enaddr);
629d39a76e7Sxw }
630d39a76e7Sxw
631d39a76e7Sxw /* KLUDGE ALERT. HARD WIRED TO PORT ZERO */
632d39a76e7Sxw unsigned char *
pe_get_mac(ch_t * sa)633d39a76e7Sxw pe_get_mac(ch_t *sa)
634d39a76e7Sxw {
635d39a76e7Sxw return (sa->port[0].enaddr);
636d39a76e7Sxw }
637d39a76e7Sxw
638d39a76e7Sxw /* KLUDGE ALERT. HARD WIRED TO ONE PORT */
639d39a76e7Sxw void
pe_set_promiscuous(ch_t * sa,int flag)640d39a76e7Sxw pe_set_promiscuous(ch_t *sa, int flag)
641d39a76e7Sxw {
642d39a76e7Sxw struct cmac *mac = sa->port[0].mac;
643d39a76e7Sxw struct t1_rx_mode rm;
644d39a76e7Sxw
645d39a76e7Sxw switch (flag) {
646d39a76e7Sxw case 0: /* turn off promiscuous mode */
647d39a76e7Sxw sa->ch_flags &= ~(PEPROMISC|PEALLMULTI);
648d39a76e7Sxw break;
649d39a76e7Sxw
650d39a76e7Sxw case 1: /* turn on promiscuous mode */
651d39a76e7Sxw sa->ch_flags |= PEPROMISC;
652d39a76e7Sxw break;
653d39a76e7Sxw
654d39a76e7Sxw case 2: /* turn on multicast reception */
655d39a76e7Sxw sa->ch_flags |= PEALLMULTI;
656d39a76e7Sxw break;
657d39a76e7Sxw }
658d39a76e7Sxw
659d39a76e7Sxw mutex_enter(&sa->ch_mc_lck);
660d39a76e7Sxw rm.chp = sa;
661d39a76e7Sxw rm.mc = sa->ch_mc;
662d39a76e7Sxw
663d39a76e7Sxw mac->ops->set_rx_mode(mac, &rm);
664d39a76e7Sxw mutex_exit(&sa->ch_mc_lck);
665d39a76e7Sxw }
666d39a76e7Sxw
667d39a76e7Sxw int
pe_set_mc(ch_t * sa,uint8_t * ep,int flg)668d39a76e7Sxw pe_set_mc(ch_t *sa, uint8_t *ep, int flg)
669d39a76e7Sxw {
670d39a76e7Sxw struct cmac *mac = sa->port[0].mac;
671d39a76e7Sxw struct t1_rx_mode rm;
672d39a76e7Sxw
673d39a76e7Sxw if (flg == GLD_MULTI_ENABLE) {
674d39a76e7Sxw ch_mc_t *mcp;
675d39a76e7Sxw
676d39a76e7Sxw mcp = (ch_mc_t *)kmem_zalloc(sizeof (struct ch_mc),
677d39a76e7Sxw KM_NOSLEEP);
678d39a76e7Sxw if (mcp == NULL)
679d39a76e7Sxw return (GLD_NORESOURCES);
680d39a76e7Sxw
681d39a76e7Sxw bcopy(ep, &mcp->cmc_mca, 6);
682d39a76e7Sxw
683d39a76e7Sxw mutex_enter(&sa->ch_mc_lck);
684d39a76e7Sxw mcp->cmc_next = sa->ch_mc;
685d39a76e7Sxw sa->ch_mc = mcp;
686d39a76e7Sxw sa->ch_mc_cnt++;
687d39a76e7Sxw mutex_exit(&sa->ch_mc_lck);
688d39a76e7Sxw
689d39a76e7Sxw } else if (flg == GLD_MULTI_DISABLE) {
690d39a76e7Sxw ch_mc_t **p = &sa->ch_mc;
691d39a76e7Sxw ch_mc_t *q = NULL;
692d39a76e7Sxw
693d39a76e7Sxw mutex_enter(&sa->ch_mc_lck);
694d39a76e7Sxw p = &sa->ch_mc;
695d39a76e7Sxw while (*p) {
696d39a76e7Sxw if (bcmp(ep, (*p)->cmc_mca, 6) == 0) {
697d39a76e7Sxw q = *p;
698d39a76e7Sxw *p = (*p)->cmc_next;
699d39a76e7Sxw kmem_free(q, sizeof (*q));
700d39a76e7Sxw sa->ch_mc_cnt--;
701d39a76e7Sxw break;
702d39a76e7Sxw }
703d39a76e7Sxw
704d39a76e7Sxw p = &(*p)->cmc_next;
705d39a76e7Sxw }
706d39a76e7Sxw mutex_exit(&sa->ch_mc_lck);
707d39a76e7Sxw
708d39a76e7Sxw if (q == NULL)
709d39a76e7Sxw return (GLD_BADARG);
710d39a76e7Sxw } else
711d39a76e7Sxw return (GLD_BADARG);
712d39a76e7Sxw
713d39a76e7Sxw mutex_enter(&sa->ch_mc_lck);
714d39a76e7Sxw rm.chp = sa;
715d39a76e7Sxw rm.mc = sa->ch_mc;
716d39a76e7Sxw
717d39a76e7Sxw mac->ops->set_rx_mode(mac, &rm);
718d39a76e7Sxw mutex_exit(&sa->ch_mc_lck);
719d39a76e7Sxw
720d39a76e7Sxw return (GLD_SUCCESS);
721d39a76e7Sxw }
722d39a76e7Sxw
723d39a76e7Sxw /*
724d39a76e7Sxw * return: speed - bandwidth of interface
725d39a76e7Sxw * return: intrcnt - # interrupts
726d39a76e7Sxw * return: norcvbuf - # recedived packets dropped by driver
727d39a76e7Sxw * return: oerrors - # bad send packets
728d39a76e7Sxw * return: ierrors - # bad receive packets
729d39a76e7Sxw * return: underrun - # bad underrun xmit packets
730d39a76e7Sxw * return: overrun - # bad overrun recv packets
731d39a76e7Sxw * return: framing - # bad aligned recv packets
732d39a76e7Sxw * return: crc - # bad FCS (crc) recv packets
733d39a76e7Sxw * return: carrier - times carrier was lost
734d39a76e7Sxw * return: collisions - # xmit collisions
735d39a76e7Sxw * return: xcollisions - # xmit pkts dropped due to collisions
736d39a76e7Sxw * return: late - # late xmit collisions
737d39a76e7Sxw * return: defer - # deferred xmit packets
738d39a76e7Sxw * return: xerrs - # xmit dropped packets
739d39a76e7Sxw * return: rerrs - # recv dropped packets
740d39a76e7Sxw * return: toolong - # recv pkts too long
741d39a76e7Sxw * return: runt - # recv runt pkts
742d39a76e7Sxw * return: multixmt - # multicast pkts xmitted
743d39a76e7Sxw * return: multircv - # multicast pkts recved
744d39a76e7Sxw * return: brdcstxmt - # broadcast pkts xmitted
745d39a76e7Sxw * return: brdcstrcv - # broadcast pkts rcv
746d39a76e7Sxw */
747d39a76e7Sxw
748d39a76e7Sxw int
pe_get_stats(ch_t * sa,uint64_t * speed,uint32_t * intrcnt,uint32_t * norcvbuf,uint32_t * oerrors,uint32_t * ierrors,uint32_t * underrun,uint32_t * overrun,uint32_t * framing,uint32_t * crc,uint32_t * carrier,uint32_t * collisions,uint32_t * xcollisions,uint32_t * late,uint32_t * defer,uint32_t * xerrs,uint32_t * rerrs,uint32_t * toolong,uint32_t * runt,ulong_t * multixmt,ulong_t * multircv,ulong_t * brdcstxmt,ulong_t * brdcstrcv)749d39a76e7Sxw pe_get_stats(ch_t *sa, uint64_t *speed, uint32_t *intrcnt, uint32_t *norcvbuf,
750d39a76e7Sxw uint32_t *oerrors, uint32_t *ierrors, uint32_t *underrun,
751d39a76e7Sxw uint32_t *overrun, uint32_t *framing, uint32_t *crc,
752d39a76e7Sxw uint32_t *carrier, uint32_t *collisions, uint32_t *xcollisions,
753d39a76e7Sxw uint32_t *late, uint32_t *defer, uint32_t *xerrs, uint32_t *rerrs,
754d39a76e7Sxw uint32_t *toolong, uint32_t *runt, ulong_t *multixmt, ulong_t *multircv,
755d39a76e7Sxw ulong_t *brdcstxmt, ulong_t *brdcstrcv)
756d39a76e7Sxw {
757d39a76e7Sxw struct pe_port_t *pt;
758d39a76e7Sxw int line_speed;
759d39a76e7Sxw int line_duplex;
760d39a76e7Sxw int line_is_active;
761d39a76e7Sxw uint64_t v;
762d39a76e7Sxw const struct cmac_statistics *sp;
763d39a76e7Sxw
764d39a76e7Sxw pt = &(sa->port[0]);
765d39a76e7Sxw (void) pt->phy->ops->get_link_status(pt->phy,
766d39a76e7Sxw &line_is_active, &line_speed, &line_duplex, NULL);
767d39a76e7Sxw
768d39a76e7Sxw switch (line_speed) {
769d39a76e7Sxw case SPEED_10:
770d39a76e7Sxw *speed = 10000000;
771d39a76e7Sxw break;
772d39a76e7Sxw case SPEED_100:
773d39a76e7Sxw *speed = 100000000;
774d39a76e7Sxw break;
775d39a76e7Sxw case SPEED_1000:
776d39a76e7Sxw *speed = 1000000000;
777d39a76e7Sxw break;
778d39a76e7Sxw case SPEED_10000:
779d39a76e7Sxw /*
780d39a76e7Sxw * kludge to get 10,000,000,000 constant (and keep
781d39a76e7Sxw * compiler happy).
782d39a76e7Sxw */
783d39a76e7Sxw v = 10000000;
784d39a76e7Sxw v *= 1000;
785d39a76e7Sxw *speed = v;
786d39a76e7Sxw break;
787d39a76e7Sxw default:
788d39a76e7Sxw goto error;
789d39a76e7Sxw }
790d39a76e7Sxw
791d39a76e7Sxw *intrcnt = sa->isr_intr;
792d39a76e7Sxw *norcvbuf = sa->norcvbuf;
793d39a76e7Sxw
794d39a76e7Sxw sp = sa->port[0].mac->ops->statistics_update(sa->port[0].mac,
795d39a76e7Sxw MAC_STATS_UPDATE_FULL);
796d39a76e7Sxw
797d39a76e7Sxw *ierrors = sp->RxOctetsBad;
798d39a76e7Sxw
799d39a76e7Sxw /*
800d39a76e7Sxw * not sure this is correct. # aborted at driver level +
801d39a76e7Sxw * # at hardware level
802d39a76e7Sxw */
803d39a76e7Sxw *oerrors = sa->oerr + sp->TxFramesAbortedDueToXSCollisions +
804d39a76e7Sxw sp->TxUnderrun + sp->TxLengthErrors +
805d39a76e7Sxw sp->TxInternalMACXmitError +
806d39a76e7Sxw sp->TxFramesWithExcessiveDeferral +
807d39a76e7Sxw sp->TxFCSErrors;
808d39a76e7Sxw
809d39a76e7Sxw *underrun = sp->TxUnderrun;
810d39a76e7Sxw *overrun = sp->RxFrameTooLongErrors;
811d39a76e7Sxw *framing = sp->RxAlignErrors;
812d39a76e7Sxw *crc = sp->RxFCSErrors;
813d39a76e7Sxw *carrier = 0; /* need to find this */
814d39a76e7Sxw *collisions = sp->TxTotalCollisions;
815d39a76e7Sxw *xcollisions = sp->TxFramesAbortedDueToXSCollisions;
816d39a76e7Sxw *late = sp->TxLateCollisions;
817d39a76e7Sxw *defer = sp->TxFramesWithDeferredXmissions;
818d39a76e7Sxw *xerrs = sp->TxUnderrun + sp->TxLengthErrors +
819d39a76e7Sxw sp->TxInternalMACXmitError + sp->TxFCSErrors;
820d39a76e7Sxw *rerrs = sp->RxSymbolErrors + sp->RxSequenceErrors + sp->RxRuntErrors +
821d39a76e7Sxw sp->RxJabberErrors + sp->RxInternalMACRcvError +
822d39a76e7Sxw sp->RxInRangeLengthErrors + sp->RxOutOfRangeLengthField;
823d39a76e7Sxw *toolong = sp->RxFrameTooLongErrors;
824d39a76e7Sxw *runt = sp->RxRuntErrors;
825d39a76e7Sxw
826d39a76e7Sxw *multixmt = sp->TxMulticastFramesOK;
827d39a76e7Sxw *multircv = sp->RxMulticastFramesOK;
828d39a76e7Sxw *brdcstxmt = sp->TxBroadcastFramesOK;
829d39a76e7Sxw *brdcstrcv = sp->RxBroadcastFramesOK;
830d39a76e7Sxw
831d39a76e7Sxw return (0);
832d39a76e7Sxw
833d39a76e7Sxw error:
834d39a76e7Sxw *speed = 0;
835d39a76e7Sxw *intrcnt = 0;
836d39a76e7Sxw *norcvbuf = 0;
837d39a76e7Sxw *norcvbuf = 0;
838d39a76e7Sxw *oerrors = 0;
839d39a76e7Sxw *ierrors = 0;
840d39a76e7Sxw *underrun = 0;
841d39a76e7Sxw *overrun = 0;
842d39a76e7Sxw *framing = 0;
843d39a76e7Sxw *crc = 0;
844d39a76e7Sxw *carrier = 0;
845d39a76e7Sxw *collisions = 0;
846d39a76e7Sxw *xcollisions = 0;
847d39a76e7Sxw *late = 0;
848d39a76e7Sxw *defer = 0;
849d39a76e7Sxw *xerrs = 0;
850d39a76e7Sxw *rerrs = 0;
851d39a76e7Sxw *toolong = 0;
852d39a76e7Sxw *runt = 0;
853d39a76e7Sxw *multixmt = 0;
854d39a76e7Sxw *multircv = 0;
855d39a76e7Sxw *brdcstxmt = 0;
856d39a76e7Sxw *brdcstrcv = 0;
857d39a76e7Sxw
858d39a76e7Sxw return (1);
859d39a76e7Sxw }
860d39a76e7Sxw
861d39a76e7Sxw uint32_t ch_gtm = 0; /* Default: Global Tunnel Mode off */
862d39a76e7Sxw uint32_t ch_global_config = 0x07000000; /* Default: errors, warnings, status */
863d39a76e7Sxw uint32_t ch_is_asic = 0; /* Default: non-ASIC */
864d39a76e7Sxw uint32_t ch_link_speed = PE_LINK_SPEED_AUTONEG; /* Default: auto-negoiate */
865d39a76e7Sxw uint32_t ch_num_of_ports = 1; /* Default: 1 port */
866d39a76e7Sxw uint32_t ch_tp_reset_cm = 1; /* Default: reset CM memory map */
867d39a76e7Sxw uint32_t ch_phy_tx_fifo = 0; /* Default: 0 phy tx fifo depth */
868d39a76e7Sxw uint32_t ch_phy_rx_fifo = 0; /* Default: 0 phy rx fifo depth */
869d39a76e7Sxw uint32_t ch_phy_force_master = 1; /* Default: link always master mode */
870d39a76e7Sxw uint32_t ch_mc5_rtbl_size = 2048; /* Default: TCAM routing table size */
871d39a76e7Sxw uint32_t ch_mc5_dbsvr_size = 128; /* Default: TCAM server size */
872d39a76e7Sxw uint32_t ch_mc5_parity = 1; /* Default: parity error checking */
873d39a76e7Sxw uint32_t ch_mc5_issue_syn = 0; /* Default: Allow transaction overlap */
874d39a76e7Sxw uint32_t ch_packet_tracing = 0; /* Default: no packet tracing */
875d39a76e7Sxw uint32_t ch_server_region_len =
876d39a76e7Sxw DEFAULT_SERVER_REGION_LEN;
877d39a76e7Sxw uint32_t ch_rt_region_len =
878d39a76e7Sxw DEFAULT_RT_REGION_LEN;
879d39a76e7Sxw uint32_t ch_offload_ip_cksum = 0; /* Default: no checksum offloading */
880d39a76e7Sxw uint32_t ch_offload_udp_cksum = 1; /* Default: offload UDP ckecksum */
881d39a76e7Sxw uint32_t ch_offload_tcp_cksum = 1; /* Default: offload TCP checksum */
882d39a76e7Sxw uint32_t ch_sge_cmdq_threshold = 0; /* Default: threshold 0 */
883d39a76e7Sxw uint32_t ch_sge_flq_threshold = 0; /* Default: SGE flq threshold */
884d39a76e7Sxw uint32_t ch_sge_cmdq0_cnt = /* Default: cmd queue 0 size */
885d39a76e7Sxw SGE_CMDQ0_CNT;
886d39a76e7Sxw uint32_t ch_sge_cmdq1_cnt = /* Default: cmd queue 1 size */
887d39a76e7Sxw SGE_CMDQ0_CNT;
888d39a76e7Sxw uint32_t ch_sge_flq0_cnt = /* Default: free list queue-0 length */
889d39a76e7Sxw SGE_FLQ0_CNT;
890d39a76e7Sxw uint32_t ch_sge_flq1_cnt = /* Default: free list queue-1 length */
891d39a76e7Sxw SGE_FLQ0_CNT;
892d39a76e7Sxw uint32_t ch_sge_respq_cnt = /* Default: reqsponse queue size */
893d39a76e7Sxw SGE_RESPQ_CNT;
894d39a76e7Sxw uint32_t ch_stats = 1; /* Default: Automatic Update MAC stats */
895d39a76e7Sxw uint32_t ch_tx_delay_us = 0; /* Default: No Msec delay to Tx pkts */
896d39a76e7Sxw int32_t ch_chip = -1; /* Default: use hardware lookup tbl */
897d39a76e7Sxw uint32_t ch_exit_early = 0; /* Default: complete initialization */
898d39a76e7Sxw uint32_t ch_rb_num_of_entries = 1000; /* Default: number ring buffer entries */
899d39a76e7Sxw uint32_t ch_rb_size_of_entries = 64; /* Default: ring buffer entry size */
900d39a76e7Sxw uint32_t ch_rb_flag = 1; /* Default: ring buffer flag */
901d39a76e7Sxw uint32_t ch_type;
902d39a76e7Sxw uint64_t ch_cat_opt0 = 0;
903d39a76e7Sxw uint64_t ch_cat_opt1 = 0;
904d39a76e7Sxw uint32_t ch_timer_delay = 0; /* Default: use value from board entry */
905d39a76e7Sxw
906d39a76e7Sxw int
pe_attach(ch_t * chp)907d39a76e7Sxw pe_attach(ch_t *chp)
908d39a76e7Sxw {
909d39a76e7Sxw int return_val = 1;
910d39a76e7Sxw const struct board_info *bi;
911d39a76e7Sxw uint32_t pcix_cmd;
912d39a76e7Sxw
913d39a76e7Sxw (void) ch_set_config_data(chp);
914d39a76e7Sxw
915d39a76e7Sxw bi = pe_sa_init(chp);
916d39a76e7Sxw if (bi == 0)
917d39a76e7Sxw return (1);
918d39a76e7Sxw
919d39a76e7Sxw if (t1_init_sw_modules(chp, bi) < 0)
920d39a76e7Sxw return (1);
921d39a76e7Sxw
92211abda1eSToomas Soome if (pe_small_rbuf_pool_init(chp) == 0)
923d39a76e7Sxw return (1);
924d39a76e7Sxw
92511abda1eSToomas Soome if (pe_big_rbuf_pool_init(chp) == 0)
926d39a76e7Sxw return (1);
927d39a76e7Sxw
928d39a76e7Sxw /*
929d39a76e7Sxw * We gain significaint performance improvements when we
930d39a76e7Sxw * increase the PCI's maximum memory read byte count to
931d39a76e7Sxw * 2K(HW doesn't support 4K at this time) and set the PCI's
932d39a76e7Sxw * maximum outstanding split transactions to 4. We want to do
933d39a76e7Sxw * this for 10G. Done by software utility.
934d39a76e7Sxw */
935d39a76e7Sxw
936d39a76e7Sxw if (board_info(chp)->caps & SUPPORTED_10000baseT_Full) {
937d39a76e7Sxw (void) t1_os_pci_read_config_4(chp, A_PCICFG_PCIX_CMD,
938d39a76e7Sxw &pcix_cmd);
939d39a76e7Sxw /*
940d39a76e7Sxw * if the burstsize is set, then use it instead of default
941d39a76e7Sxw */
942d39a76e7Sxw if (chp->ch_config.burstsize_set) {
943d39a76e7Sxw pcix_cmd &= ~0xc0000;
944d39a76e7Sxw pcix_cmd |= (chp->ch_config.burstsize << 18);
945d39a76e7Sxw }
946d39a76e7Sxw /*
947d39a76e7Sxw * if the split transaction count is set, then use it.
948d39a76e7Sxw */
949d39a76e7Sxw if (chp->ch_config.transaction_cnt_set) {
950d39a76e7Sxw pcix_cmd &= ~ 0x700000;
951d39a76e7Sxw pcix_cmd |= (chp->ch_config.transaction_cnt << 20);
952d39a76e7Sxw }
953d39a76e7Sxw
954d39a76e7Sxw /*
955d39a76e7Sxw * set ralaxed ordering flag as configured in chxge.conf
956d39a76e7Sxw */
957d39a76e7Sxw pcix_cmd |= (chp->ch_config.relaxed_ordering << 17);
958d39a76e7Sxw
959d39a76e7Sxw (void) t1_os_pci_write_config_4(chp, A_PCICFG_PCIX_CMD,
960d39a76e7Sxw pcix_cmd);
961d39a76e7Sxw }
962d39a76e7Sxw
963d39a76e7Sxw /*
964d39a76e7Sxw * set the latency time to F8 for 10G cards.
965d39a76e7Sxw * Done by software utiltiy.
966d39a76e7Sxw */
967d39a76e7Sxw if (enable_latency_timer) {
968d39a76e7Sxw if (board_info(chp)->caps & SUPPORTED_10000baseT_Full) {
969d39a76e7Sxw (void) t1_os_pci_write_config_4(chp, 0xc, 0xf800);
970d39a76e7Sxw }
971d39a76e7Sxw }
972d39a76e7Sxw
973d39a76e7Sxw /*
974d39a76e7Sxw * update mtu table (regs: 0x404 - 0x420) with bigger values than
975d39a76e7Sxw * default.
976d39a76e7Sxw */
977d39a76e7Sxw update_mtu_tab(chp);
978d39a76e7Sxw
979d39a76e7Sxw /*
980d39a76e7Sxw * Clear all interrupts now. Don't enable
981d39a76e7Sxw * them until later.
982d39a76e7Sxw */
983d39a76e7Sxw t1_interrupts_clear(chp);
984d39a76e7Sxw
985d39a76e7Sxw /*
986d39a76e7Sxw * Function succeeded.
987d39a76e7Sxw */
988d39a76e7Sxw return_val = 0;
989d39a76e7Sxw
990d39a76e7Sxw return (return_val);
991d39a76e7Sxw }
992d39a76e7Sxw
993d39a76e7Sxw /*
994d39a76e7Sxw * DESC: Read variables set in /boot/loader.conf and save
995d39a76e7Sxw * them internally. These internal values are then
996d39a76e7Sxw * used to make decisions at run-time on behavior thus
997d39a76e7Sxw * allowing a certain level of customization.
998d39a76e7Sxw * OUT: p_config - pointer to config structure that
999d39a76e7Sxw * contains all of the new values.
1000d39a76e7Sxw * RTN: 0 - Success;
1001d39a76e7Sxw */
1002d39a76e7Sxw static int
ch_set_config_data(ch_t * chp)1003d39a76e7Sxw ch_set_config_data(ch_t *chp)
1004d39a76e7Sxw {
1005d39a76e7Sxw pe_config_data_t *p_config = (pe_config_data_t *)&chp->config_data;
1006d39a76e7Sxw
1007d39a76e7Sxw bzero(p_config, sizeof (pe_config_data_t));
1008d39a76e7Sxw
1009d39a76e7Sxw /*
1010d39a76e7Sxw * Global Tunnel Mode configuration
1011d39a76e7Sxw */
1012d39a76e7Sxw p_config->gtm = ch_gtm;
1013d39a76e7Sxw
1014d39a76e7Sxw p_config->global_config = ch_global_config;
1015d39a76e7Sxw
1016d39a76e7Sxw if (p_config->gtm)
1017d39a76e7Sxw p_config->global_config |= CFGMD_TUNNEL;
1018d39a76e7Sxw
1019d39a76e7Sxw p_config->tp_reset_cm = ch_tp_reset_cm;
1020d39a76e7Sxw p_config->is_asic = ch_is_asic;
1021d39a76e7Sxw
1022d39a76e7Sxw /*
1023d39a76e7Sxw * MC5 configuration.
1024d39a76e7Sxw */
1025d39a76e7Sxw p_config->mc5_rtbl_size = ch_mc5_rtbl_size;
1026d39a76e7Sxw p_config->mc5_dbsvr_size = ch_mc5_dbsvr_size;
1027d39a76e7Sxw p_config->mc5_parity = ch_mc5_parity;
1028d39a76e7Sxw p_config->mc5_issue_syn = ch_mc5_issue_syn;
1029d39a76e7Sxw
1030d39a76e7Sxw p_config->offload_ip_cksum = ch_offload_ip_cksum;
1031d39a76e7Sxw p_config->offload_udp_cksum = ch_offload_udp_cksum;
1032d39a76e7Sxw p_config->offload_tcp_cksum = ch_offload_tcp_cksum;
1033d39a76e7Sxw
1034d39a76e7Sxw p_config->packet_tracing = ch_packet_tracing;
1035d39a76e7Sxw
1036d39a76e7Sxw p_config->server_region_len = ch_server_region_len;
1037d39a76e7Sxw p_config->rt_region_len = ch_rt_region_len;
1038d39a76e7Sxw
1039d39a76e7Sxw /*
1040d39a76e7Sxw * Link configuration.
1041d39a76e7Sxw *
1042d39a76e7Sxw * 5-auto-neg 2-1000Gbps; 1-100Gbps; 0-10Gbps
1043d39a76e7Sxw */
1044d39a76e7Sxw p_config->link_speed = ch_link_speed;
1045d39a76e7Sxw p_config->num_of_ports = ch_num_of_ports;
1046d39a76e7Sxw
1047d39a76e7Sxw /*
1048d39a76e7Sxw * Catp options
1049d39a76e7Sxw */
1050d39a76e7Sxw p_config->cat_opt0 = ch_cat_opt0;
1051d39a76e7Sxw p_config->cat_opt1 = ch_cat_opt1;
1052d39a76e7Sxw
1053d39a76e7Sxw /*
1054d39a76e7Sxw * SGE configuration.
1055d39a76e7Sxw */
1056d39a76e7Sxw p_config->sge_cmdq0_cnt = ch_sge_cmdq0_cnt;
1057d39a76e7Sxw p_config->sge_cmdq1_cnt = ch_sge_cmdq1_cnt;
1058d39a76e7Sxw p_config->sge_flq0_cnt = ch_sge_flq0_cnt;
1059d39a76e7Sxw p_config->sge_flq1_cnt = ch_sge_flq1_cnt;
1060d39a76e7Sxw p_config->sge_respq_cnt = ch_sge_respq_cnt;
1061d39a76e7Sxw
1062d39a76e7Sxw p_config->phy_rx_fifo = ch_phy_rx_fifo;
1063d39a76e7Sxw p_config->phy_tx_fifo = ch_phy_tx_fifo;
1064d39a76e7Sxw
1065d39a76e7Sxw p_config->sge_cmdq_threshold = ch_sge_cmdq_threshold;
1066d39a76e7Sxw
1067d39a76e7Sxw p_config->sge_flq_threshold = ch_sge_flq_threshold;
1068d39a76e7Sxw
1069d39a76e7Sxw p_config->phy_force_master = ch_phy_force_master;
1070d39a76e7Sxw
1071d39a76e7Sxw p_config->rb_num_of_entries = ch_rb_num_of_entries;
1072d39a76e7Sxw
1073d39a76e7Sxw p_config->rb_size_of_entries = ch_rb_size_of_entries;
1074d39a76e7Sxw
1075d39a76e7Sxw p_config->rb_flag = ch_rb_flag;
1076d39a76e7Sxw
1077d39a76e7Sxw p_config->exit_early = ch_exit_early;
1078d39a76e7Sxw
1079d39a76e7Sxw p_config->chip = ch_chip;
1080d39a76e7Sxw
1081d39a76e7Sxw p_config->stats = ch_stats;
1082d39a76e7Sxw
1083d39a76e7Sxw p_config->tx_delay_us = ch_tx_delay_us;
1084d39a76e7Sxw
1085d39a76e7Sxw return (0);
1086d39a76e7Sxw }
1087d39a76e7Sxw
1088d39a76e7Sxw static const struct board_info *
pe_sa_init(ch_t * sa)1089d39a76e7Sxw pe_sa_init(ch_t *sa)
1090d39a76e7Sxw {
1091d39a76e7Sxw uint16_t device_id;
1092d39a76e7Sxw uint16_t device_subid;
1093d39a76e7Sxw const struct board_info *bi;
1094d39a76e7Sxw
1095d39a76e7Sxw sa->config = sa->config_data.global_config;
1096d39a76e7Sxw device_id = pci_config_get16(sa->ch_hpci, 2);
1097d39a76e7Sxw device_subid = pci_config_get16(sa->ch_hpci, 0x2e);
1098d39a76e7Sxw
1099d39a76e7Sxw bi = t1_get_board_info_from_ids(device_id, device_subid);
1100d39a76e7Sxw if (bi == NULL) {
1101d39a76e7Sxw cmn_err(CE_NOTE,
1102d39a76e7Sxw "The adapter with device_id %d %d is not supported.\n",
1103d39a76e7Sxw device_id, device_subid);
1104d39a76e7Sxw return (NULL);
1105d39a76e7Sxw }
1106d39a76e7Sxw
1107d39a76e7Sxw if (t1_get_board_rev(sa, bi, &sa->params)) {
1108d39a76e7Sxw cmn_err(CE_NOTE, "unknown device_id %d %d\n",
1109d39a76e7Sxw device_id, device_subid);
1110d39a76e7Sxw return ((const struct board_info *)NULL);
1111d39a76e7Sxw }
1112d39a76e7Sxw
1113d39a76e7Sxw return (bi);
1114d39a76e7Sxw }
1115d39a76e7Sxw
1116d39a76e7Sxw /*
1117d39a76e7Sxw * allocate pool of small receive buffers (with vaddr & paddr) and
1118d39a76e7Sxw * receiver buffer control structure (ch_esb_t *rbp).
1119d39a76e7Sxw * XXX we should allow better tuning of the # of preallocated
1120d39a76e7Sxw * free buffers against the # of freelist entries.
1121d39a76e7Sxw */
1122d39a76e7Sxw static int
pe_small_rbuf_pool_init(ch_t * sa)1123d39a76e7Sxw pe_small_rbuf_pool_init(ch_t *sa)
1124d39a76e7Sxw {
1125d39a76e7Sxw int i;
1126d39a76e7Sxw ch_esb_t *rbp;
1127d39a76e7Sxw extern uint32_t sge_flq0_cnt;
1128d39a76e7Sxw extern uint32_t sge_flq1_cnt;
1129d39a76e7Sxw int size;
1130d39a76e7Sxw uint32_t j;
1131d39a76e7Sxw
1132d39a76e7Sxw if (is_T2(sa))
1133d39a76e7Sxw size = sge_flq1_cnt * fl_sz_multiplier;
1134d39a76e7Sxw else
1135d39a76e7Sxw size = sge_flq0_cnt * fl_sz_multiplier;
1136d39a76e7Sxw
1137d39a76e7Sxw mutex_init(&sa->ch_small_esbl, NULL, MUTEX_DRIVER, sa->ch_icookp);
1138d39a76e7Sxw
1139d39a76e7Sxw mutex_enter(&in_use_l);
1140d39a76e7Sxw j = in_use_index++;
1141d39a76e7Sxw if (in_use_index >= SZ_INUSE)
1142d39a76e7Sxw in_use_index = 0;
1143d39a76e7Sxw mutex_exit(&in_use_l);
1144d39a76e7Sxw
1145d39a76e7Sxw sa->ch_small_owner = NULL;
1146d39a76e7Sxw sa->ch_sm_index = j;
1147d39a76e7Sxw sa->ch_small_esb_free = NULL;
1148d39a76e7Sxw for (i = 0; i < size; i++) {
1149d39a76e7Sxw rbp = ch_alloc_small_esbbuf(sa, j);
1150d39a76e7Sxw if (rbp == NULL)
1151d39a76e7Sxw goto error;
1152d39a76e7Sxw /*
1153d39a76e7Sxw * add entry to free list
1154d39a76e7Sxw */
1155d39a76e7Sxw rbp->cs_next = sa->ch_small_esb_free;
1156d39a76e7Sxw sa->ch_small_esb_free = rbp;
1157d39a76e7Sxw
1158d39a76e7Sxw /*
1159d39a76e7Sxw * add entry to owned list
1160d39a76e7Sxw */
1161d39a76e7Sxw rbp->cs_owner = sa->ch_small_owner;
1162d39a76e7Sxw sa->ch_small_owner = rbp;
1163d39a76e7Sxw }
1164d39a76e7Sxw return (1);
1165d39a76e7Sxw
1166d39a76e7Sxw error:
1167d39a76e7Sxw sa->ch_small_owner = NULL;
1168d39a76e7Sxw
1169d39a76e7Sxw /* free whatever we've already allocated */
1170d39a76e7Sxw pe_rbuf_pool_free(sa);
1171d39a76e7Sxw
1172d39a76e7Sxw return (0);
1173d39a76e7Sxw }
1174d39a76e7Sxw
1175d39a76e7Sxw /*
1176d39a76e7Sxw * allocate pool of receive buffers (with vaddr & paddr) and
1177d39a76e7Sxw * receiver buffer control structure (ch_esb_t *rbp).
1178d39a76e7Sxw * XXX we should allow better tuning of the # of preallocated
1179d39a76e7Sxw * free buffers against the # of freelist entries.
1180d39a76e7Sxw */
1181d39a76e7Sxw static int
pe_big_rbuf_pool_init(ch_t * sa)1182d39a76e7Sxw pe_big_rbuf_pool_init(ch_t *sa)
1183d39a76e7Sxw {
1184d39a76e7Sxw int i;
1185d39a76e7Sxw ch_esb_t *rbp;
1186d39a76e7Sxw extern uint32_t sge_flq0_cnt;
1187d39a76e7Sxw extern uint32_t sge_flq1_cnt;
1188d39a76e7Sxw int size;
1189d39a76e7Sxw uint32_t j;
1190d39a76e7Sxw
1191d39a76e7Sxw if (is_T2(sa))
1192d39a76e7Sxw size = sge_flq0_cnt * fl_sz_multiplier;
1193d39a76e7Sxw else
1194d39a76e7Sxw size = sge_flq1_cnt * fl_sz_multiplier;
1195d39a76e7Sxw
1196d39a76e7Sxw mutex_init(&sa->ch_big_esbl, NULL, MUTEX_DRIVER, sa->ch_icookp);
1197d39a76e7Sxw
1198d39a76e7Sxw mutex_enter(&in_use_l);
1199d39a76e7Sxw j = in_use_index++;
1200d39a76e7Sxw if (in_use_index >= SZ_INUSE)
1201d39a76e7Sxw in_use_index = 0;
1202d39a76e7Sxw mutex_exit(&in_use_l);
1203d39a76e7Sxw
1204d39a76e7Sxw sa->ch_big_owner = NULL;
1205d39a76e7Sxw sa->ch_big_index = j;
1206d39a76e7Sxw sa->ch_big_esb_free = NULL;
1207d39a76e7Sxw for (i = 0; i < size; i++) {
1208d39a76e7Sxw rbp = ch_alloc_big_esbbuf(sa, j);
1209d39a76e7Sxw if (rbp == NULL)
1210d39a76e7Sxw goto error;
1211d39a76e7Sxw rbp->cs_next = sa->ch_big_esb_free;
1212d39a76e7Sxw sa->ch_big_esb_free = rbp;
1213d39a76e7Sxw
1214d39a76e7Sxw /*
1215d39a76e7Sxw * add entry to owned list
1216d39a76e7Sxw */
1217d39a76e7Sxw rbp->cs_owner = sa->ch_big_owner;
1218d39a76e7Sxw sa->ch_big_owner = rbp;
1219d39a76e7Sxw }
1220d39a76e7Sxw return (1);
1221d39a76e7Sxw
1222d39a76e7Sxw error:
1223d39a76e7Sxw sa->ch_big_owner = NULL;
1224d39a76e7Sxw
1225d39a76e7Sxw /* free whatever we've already allocated */
1226d39a76e7Sxw pe_rbuf_pool_free(sa);
1227d39a76e7Sxw
1228d39a76e7Sxw return (0);
1229d39a76e7Sxw }
1230d39a76e7Sxw
1231d39a76e7Sxw /*
1232d39a76e7Sxw * allocate receive buffer structure and dma mapped buffer (SGE_SM_BUF_SZ bytes)
1233d39a76e7Sxw * note that we will DMA at a 2 byte offset for Solaris when checksum offload
1234d39a76e7Sxw * is enabled.
1235d39a76e7Sxw */
1236d39a76e7Sxw static ch_esb_t *
ch_alloc_small_esbbuf(ch_t * sa,uint32_t i)1237d39a76e7Sxw ch_alloc_small_esbbuf(ch_t *sa, uint32_t i)
1238d39a76e7Sxw {
1239d39a76e7Sxw ch_esb_t *rbp;
1240d39a76e7Sxw
1241d39a76e7Sxw rbp = (ch_esb_t *)kmem_zalloc(sizeof (ch_esb_t), KM_SLEEP);
1242d39a76e7Sxw if (rbp == NULL) {
1243d39a76e7Sxw return ((ch_esb_t *)0);
1244d39a76e7Sxw }
1245d39a76e7Sxw
1246d39a76e7Sxw #if BYTE_ORDER == BIG_ENDIAN
1247d39a76e7Sxw rbp->cs_buf = (caddr_t)ch_alloc_dma_mem(sa, 1, DMA_STREAM|DMA_SMALN,
1248d39a76e7Sxw SGE_SM_BUF_SZ(sa), &rbp->cs_pa, &rbp->cs_dh, &rbp->cs_ah);
1249d39a76e7Sxw #else
1250d39a76e7Sxw rbp->cs_buf = (caddr_t)ch_alloc_dma_mem(sa, 0, DMA_STREAM|DMA_SMALN,
1251d39a76e7Sxw SGE_SM_BUF_SZ(sa), &rbp->cs_pa, &rbp->cs_dh, &rbp->cs_ah);
1252d39a76e7Sxw #endif
1253d39a76e7Sxw
1254d39a76e7Sxw if (rbp->cs_buf == NULL) {
1255d39a76e7Sxw kmem_free(rbp, sizeof (ch_esb_t));
1256d39a76e7Sxw return ((ch_esb_t *)0);
1257d39a76e7Sxw }
1258d39a76e7Sxw
1259d39a76e7Sxw rbp->cs_sa = sa;
1260d39a76e7Sxw rbp->cs_index = i;
1261d39a76e7Sxw
1262d39a76e7Sxw rbp->cs_frtn.free_func = (void (*)())&ch_small_rbuf_recycle;
1263d39a76e7Sxw rbp->cs_frtn.free_arg = (caddr_t)rbp;
1264d39a76e7Sxw
1265d39a76e7Sxw return (rbp);
1266d39a76e7Sxw }
1267d39a76e7Sxw
1268d39a76e7Sxw /*
1269d39a76e7Sxw * allocate receive buffer structure and dma mapped buffer (SGE_BG_BUF_SZ bytes)
1270d39a76e7Sxw * note that we will DMA at a 2 byte offset for Solaris when checksum offload
1271d39a76e7Sxw * is enabled.
1272d39a76e7Sxw */
1273d39a76e7Sxw static ch_esb_t *
ch_alloc_big_esbbuf(ch_t * sa,uint32_t i)1274d39a76e7Sxw ch_alloc_big_esbbuf(ch_t *sa, uint32_t i)
1275d39a76e7Sxw {
1276d39a76e7Sxw ch_esb_t *rbp;
1277d39a76e7Sxw
1278d39a76e7Sxw rbp = (ch_esb_t *)kmem_zalloc(sizeof (ch_esb_t), KM_SLEEP);
1279d39a76e7Sxw if (rbp == NULL) {
1280d39a76e7Sxw return ((ch_esb_t *)0);
1281d39a76e7Sxw }
1282d39a76e7Sxw
1283d39a76e7Sxw #if BYTE_ORDER == BIG_ENDIAN
1284d39a76e7Sxw rbp->cs_buf = (caddr_t)ch_alloc_dma_mem(sa, 1, DMA_STREAM|DMA_BGALN,
1285d39a76e7Sxw SGE_BG_BUF_SZ(sa), &rbp->cs_pa, &rbp->cs_dh, &rbp->cs_ah);
1286d39a76e7Sxw #else
1287d39a76e7Sxw rbp->cs_buf = (caddr_t)ch_alloc_dma_mem(sa, 0, DMA_STREAM|DMA_BGALN,
1288d39a76e7Sxw SGE_BG_BUF_SZ(sa), &rbp->cs_pa, &rbp->cs_dh, &rbp->cs_ah);
1289d39a76e7Sxw #endif
1290d39a76e7Sxw
1291d39a76e7Sxw if (rbp->cs_buf == NULL) {
1292d39a76e7Sxw kmem_free(rbp, sizeof (ch_esb_t));
1293d39a76e7Sxw return ((ch_esb_t *)0);
1294d39a76e7Sxw }
1295d39a76e7Sxw
1296d39a76e7Sxw rbp->cs_sa = sa;
1297d39a76e7Sxw rbp->cs_index = i;
1298d39a76e7Sxw
1299d39a76e7Sxw rbp->cs_frtn.free_func = (void (*)())&ch_big_rbuf_recycle;
1300d39a76e7Sxw rbp->cs_frtn.free_arg = (caddr_t)rbp;
1301d39a76e7Sxw
1302d39a76e7Sxw return (rbp);
1303d39a76e7Sxw }
1304d39a76e7Sxw
1305d39a76e7Sxw /*
1306d39a76e7Sxw * free entries on the receive buffer list.
1307d39a76e7Sxw */
1308d39a76e7Sxw void
pe_rbuf_pool_free(ch_t * sa)1309d39a76e7Sxw pe_rbuf_pool_free(ch_t *sa)
1310d39a76e7Sxw {
1311d39a76e7Sxw ch_esb_t *rbp;
1312d39a76e7Sxw
1313d39a76e7Sxw mutex_enter(&sa->ch_small_esbl);
1314d39a76e7Sxw
1315d39a76e7Sxw /*
1316d39a76e7Sxw * Now set-up the rest to commit suicide.
1317d39a76e7Sxw */
1318d39a76e7Sxw while (sa->ch_small_owner) {
1319d39a76e7Sxw rbp = sa->ch_small_owner;
1320d39a76e7Sxw sa->ch_small_owner = rbp->cs_owner;
1321d39a76e7Sxw rbp->cs_owner = NULL;
1322d39a76e7Sxw rbp->cs_flag = 1;
1323d39a76e7Sxw }
1324d39a76e7Sxw
1325d39a76e7Sxw while ((rbp = sa->ch_small_esb_free) != NULL) {
1326d39a76e7Sxw /* advance head ptr to next entry */
1327d39a76e7Sxw sa->ch_small_esb_free = rbp->cs_next;
1328d39a76e7Sxw /* free private buffer allocated in ch_alloc_esbbuf() */
1329d39a76e7Sxw ch_free_dma_mem(rbp->cs_dh, rbp->cs_ah);
1330d39a76e7Sxw /* free descripter buffer */
1331d39a76e7Sxw kmem_free(rbp, sizeof (ch_esb_t));
1332d39a76e7Sxw }
1333d39a76e7Sxw
1334d39a76e7Sxw mutex_exit(&sa->ch_small_esbl);
1335d39a76e7Sxw
1336d39a76e7Sxw /* destroy ch_esbl lock */
1337d39a76e7Sxw mutex_destroy(&sa->ch_small_esbl);
1338d39a76e7Sxw
1339d39a76e7Sxw
1340d39a76e7Sxw mutex_enter(&sa->ch_big_esbl);
1341d39a76e7Sxw
1342d39a76e7Sxw /*
1343d39a76e7Sxw * Now set-up the rest to commit suicide.
1344d39a76e7Sxw */
1345d39a76e7Sxw while (sa->ch_big_owner) {
1346d39a76e7Sxw rbp = sa->ch_big_owner;
1347d39a76e7Sxw sa->ch_big_owner = rbp->cs_owner;
1348d39a76e7Sxw rbp->cs_owner = NULL;
1349d39a76e7Sxw rbp->cs_flag = 1;
1350d39a76e7Sxw }
1351d39a76e7Sxw
1352d39a76e7Sxw while ((rbp = sa->ch_big_esb_free) != NULL) {
1353d39a76e7Sxw /* advance head ptr to next entry */
1354d39a76e7Sxw sa->ch_big_esb_free = rbp->cs_next;
1355d39a76e7Sxw /* free private buffer allocated in ch_alloc_esbbuf() */
1356d39a76e7Sxw ch_free_dma_mem(rbp->cs_dh, rbp->cs_ah);
1357d39a76e7Sxw /* free descripter buffer */
1358d39a76e7Sxw kmem_free(rbp, sizeof (ch_esb_t));
1359d39a76e7Sxw }
1360d39a76e7Sxw
1361d39a76e7Sxw mutex_exit(&sa->ch_big_esbl);
1362d39a76e7Sxw
1363d39a76e7Sxw /* destroy ch_esbl lock */
1364d39a76e7Sxw mutex_destroy(&sa->ch_big_esbl);
1365d39a76e7Sxw }
1366d39a76e7Sxw
1367d39a76e7Sxw void
ch_small_rbuf_recycle(ch_esb_t * rbp)1368d39a76e7Sxw ch_small_rbuf_recycle(ch_esb_t *rbp)
1369d39a76e7Sxw {
1370d39a76e7Sxw ch_t *sa = rbp->cs_sa;
1371d39a76e7Sxw
1372d39a76e7Sxw if (rbp->cs_flag) {
1373d39a76e7Sxw uint32_t i;
1374d39a76e7Sxw /*
1375d39a76e7Sxw * free private buffer allocated in ch_alloc_esbbuf()
1376d39a76e7Sxw */
1377d39a76e7Sxw ch_free_dma_mem(rbp->cs_dh, rbp->cs_ah);
1378d39a76e7Sxw
1379d39a76e7Sxw i = rbp->cs_index;
1380d39a76e7Sxw
1381d39a76e7Sxw /*
1382d39a76e7Sxw * free descripter buffer
1383d39a76e7Sxw */
1384d39a76e7Sxw kmem_free(rbp, sizeof (ch_esb_t));
1385d39a76e7Sxw
1386d39a76e7Sxw /*
1387d39a76e7Sxw * decrement count of receive buffers freed by callback
1388d39a76e7Sxw * We decrement here so anyone trying to do fini will
1389d39a76e7Sxw * only remove the driver once the counts go to 0.
1390d39a76e7Sxw */
13911a5e258fSJosef 'Jeff' Sipek atomic_dec_32(&buffers_in_use[i]);
1392d39a76e7Sxw
1393d39a76e7Sxw return;
1394d39a76e7Sxw }
1395d39a76e7Sxw
1396d39a76e7Sxw mutex_enter(&sa->ch_small_esbl);
1397d39a76e7Sxw rbp->cs_next = sa->ch_small_esb_free;
1398d39a76e7Sxw sa->ch_small_esb_free = rbp;
1399d39a76e7Sxw mutex_exit(&sa->ch_small_esbl);
1400d39a76e7Sxw
1401d39a76e7Sxw /*
1402d39a76e7Sxw * decrement count of receive buffers freed by callback
1403d39a76e7Sxw */
14041a5e258fSJosef 'Jeff' Sipek atomic_dec_32(&buffers_in_use[rbp->cs_index]);
1405d39a76e7Sxw }
1406d39a76e7Sxw
1407d39a76e7Sxw /*
1408d39a76e7Sxw * callback function from freeb() when esballoced mblk freed.
1409d39a76e7Sxw */
1410d39a76e7Sxw void
ch_big_rbuf_recycle(ch_esb_t * rbp)1411d39a76e7Sxw ch_big_rbuf_recycle(ch_esb_t *rbp)
1412d39a76e7Sxw {
1413d39a76e7Sxw ch_t *sa = rbp->cs_sa;
1414d39a76e7Sxw
1415d39a76e7Sxw if (rbp->cs_flag) {
1416d39a76e7Sxw uint32_t i;
1417d39a76e7Sxw /*
1418d39a76e7Sxw * free private buffer allocated in ch_alloc_esbbuf()
1419d39a76e7Sxw */
1420d39a76e7Sxw ch_free_dma_mem(rbp->cs_dh, rbp->cs_ah);
1421d39a76e7Sxw
1422d39a76e7Sxw i = rbp->cs_index;
1423d39a76e7Sxw
1424d39a76e7Sxw /*
1425d39a76e7Sxw * free descripter buffer
1426d39a76e7Sxw */
1427d39a76e7Sxw kmem_free(rbp, sizeof (ch_esb_t));
1428d39a76e7Sxw
1429d39a76e7Sxw /*
1430d39a76e7Sxw * decrement count of receive buffers freed by callback
1431d39a76e7Sxw * We decrement here so anyone trying to do fini will
1432d39a76e7Sxw * only remove the driver once the counts go to 0.
1433d39a76e7Sxw */
14341a5e258fSJosef 'Jeff' Sipek atomic_dec_32(&buffers_in_use[i]);
1435d39a76e7Sxw
1436d39a76e7Sxw return;
1437d39a76e7Sxw }
1438d39a76e7Sxw
1439d39a76e7Sxw mutex_enter(&sa->ch_big_esbl);
1440d39a76e7Sxw rbp->cs_next = sa->ch_big_esb_free;
1441d39a76e7Sxw sa->ch_big_esb_free = rbp;
1442d39a76e7Sxw mutex_exit(&sa->ch_big_esbl);
1443d39a76e7Sxw
1444d39a76e7Sxw /*
1445d39a76e7Sxw * decrement count of receive buffers freed by callback
1446d39a76e7Sxw */
14471a5e258fSJosef 'Jeff' Sipek atomic_dec_32(&buffers_in_use[rbp->cs_index]);
1448d39a76e7Sxw }
1449d39a76e7Sxw
1450d39a76e7Sxw /*
1451d39a76e7Sxw * get a pre-allocated, pre-mapped receive buffer from free list.
1452d39a76e7Sxw * (used sge.c)
1453d39a76e7Sxw */
1454d39a76e7Sxw ch_esb_t *
ch_get_small_rbuf(ch_t * sa)1455d39a76e7Sxw ch_get_small_rbuf(ch_t *sa)
1456d39a76e7Sxw {
1457d39a76e7Sxw ch_esb_t *rbp;
1458d39a76e7Sxw
1459d39a76e7Sxw mutex_enter(&sa->ch_small_esbl);
1460d39a76e7Sxw rbp = sa->ch_small_esb_free;
1461d39a76e7Sxw if (rbp) {
1462d39a76e7Sxw sa->ch_small_esb_free = rbp->cs_next;
1463d39a76e7Sxw }
1464d39a76e7Sxw mutex_exit(&sa->ch_small_esbl);
1465d39a76e7Sxw
1466d39a76e7Sxw return (rbp);
1467d39a76e7Sxw }
1468d39a76e7Sxw
1469d39a76e7Sxw /*
1470d39a76e7Sxw * get a pre-allocated, pre-mapped receive buffer from free list.
1471d39a76e7Sxw * (used sge.c)
1472d39a76e7Sxw */
1473d39a76e7Sxw
1474d39a76e7Sxw ch_esb_t *
ch_get_big_rbuf(ch_t * sa)1475d39a76e7Sxw ch_get_big_rbuf(ch_t *sa)
1476d39a76e7Sxw {
1477d39a76e7Sxw ch_esb_t *rbp;
1478d39a76e7Sxw
1479d39a76e7Sxw mutex_enter(&sa->ch_big_esbl);
1480d39a76e7Sxw rbp = sa->ch_big_esb_free;
1481d39a76e7Sxw if (rbp) {
1482d39a76e7Sxw sa->ch_big_esb_free = rbp->cs_next;
1483d39a76e7Sxw }
1484d39a76e7Sxw mutex_exit(&sa->ch_big_esbl);
1485d39a76e7Sxw
1486d39a76e7Sxw return (rbp);
1487d39a76e7Sxw }
1488d39a76e7Sxw
1489d39a76e7Sxw void
pe_detach(ch_t * sa)1490d39a76e7Sxw pe_detach(ch_t *sa)
1491d39a76e7Sxw {
1492d39a76e7Sxw (void) sge_stop(sa->sge);
1493d39a76e7Sxw
1494d39a76e7Sxw pe_free_driver_resources(sa);
1495d39a76e7Sxw }
1496d39a76e7Sxw
1497d39a76e7Sxw static void
pe_free_driver_resources(ch_t * sa)1498d39a76e7Sxw pe_free_driver_resources(ch_t *sa)
1499d39a76e7Sxw {
1500d39a76e7Sxw if (sa) {
1501d39a76e7Sxw t1_free_sw_modules(sa);
1502d39a76e7Sxw
1503d39a76e7Sxw /* free pool of receive buffers */
1504d39a76e7Sxw pe_rbuf_pool_free(sa);
1505d39a76e7Sxw }
1506d39a76e7Sxw }
1507d39a76e7Sxw
1508d39a76e7Sxw /*
1509d39a76e7Sxw * Processes elmer0 external interrupts in process context.
1510d39a76e7Sxw */
1511d39a76e7Sxw static void
ext_intr_task(ch_t * adapter)1512d39a76e7Sxw ext_intr_task(ch_t *adapter)
1513d39a76e7Sxw {
1514d39a76e7Sxw u32 enable;
1515d39a76e7Sxw
1516d39a76e7Sxw (void) elmer0_ext_intr_handler(adapter);
1517d39a76e7Sxw
1518d39a76e7Sxw /* Now reenable external interrupts */
1519d39a76e7Sxw t1_write_reg_4(adapter, A_PL_CAUSE, F_PL_INTR_EXT);
1520d39a76e7Sxw enable = t1_read_reg_4(adapter, A_PL_ENABLE);
1521d39a76e7Sxw t1_write_reg_4(adapter, A_PL_ENABLE, enable | F_PL_INTR_EXT);
1522d39a76e7Sxw adapter->slow_intr_mask |= F_PL_INTR_EXT;
1523d39a76e7Sxw }
1524d39a76e7Sxw
1525d39a76e7Sxw /*
1526d39a76e7Sxw * Interrupt-context handler for elmer0 external interrupts.
1527d39a76e7Sxw */
1528d39a76e7Sxw void
t1_os_elmer0_ext_intr(ch_t * adapter)1529d39a76e7Sxw t1_os_elmer0_ext_intr(ch_t *adapter)
1530d39a76e7Sxw {
1531d39a76e7Sxw u32 enable = t1_read_reg_4(adapter, A_PL_ENABLE);
1532d39a76e7Sxw
1533d39a76e7Sxw adapter->slow_intr_mask &= ~F_PL_INTR_EXT;
1534d39a76e7Sxw t1_write_reg_4(adapter, A_PL_ENABLE, enable & ~F_PL_INTR_EXT);
1535d39a76e7Sxw #ifdef NOTYET
1536d39a76e7Sxw schedule_work(&adapter->ext_intr_handler_task);
1537d39a76e7Sxw #else
1538d39a76e7Sxw ext_intr_task(adapter);
1539d39a76e7Sxw #endif
1540d39a76e7Sxw }
1541d39a76e7Sxw
1542d39a76e7Sxw uint8_t *
t1_get_next_mcaddr(struct t1_rx_mode * rmp)1543d39a76e7Sxw t1_get_next_mcaddr(struct t1_rx_mode *rmp)
1544d39a76e7Sxw {
1545d39a76e7Sxw uint8_t *addr = 0;
1546d39a76e7Sxw if (rmp->mc) {
1547d39a76e7Sxw addr = rmp->mc->cmc_mca;
1548d39a76e7Sxw rmp->mc = rmp->mc->cmc_next;
1549d39a76e7Sxw }
1550d39a76e7Sxw return (addr);
1551d39a76e7Sxw }
1552d39a76e7Sxw
1553d39a76e7Sxw void
pe_dma_handle_init(ch_t * chp,int cnt)1554d39a76e7Sxw pe_dma_handle_init(ch_t *chp, int cnt)
1555d39a76e7Sxw {
1556d39a76e7Sxw free_dh_t *dhe;
1557d39a76e7Sxw #if defined(__sparc)
1558d39a76e7Sxw int tcnt = cnt/2;
1559d39a76e7Sxw
1560d39a76e7Sxw for (; cnt; cnt--) {
1561d39a76e7Sxw dhe = ch_get_dvma_handle(chp);
1562d39a76e7Sxw if (dhe == NULL)
1563d39a76e7Sxw break;
1564d39a76e7Sxw mutex_enter(&chp->ch_dh_lck);
1565d39a76e7Sxw dhe->dhe_next = chp->ch_vdh;
1566d39a76e7Sxw chp->ch_vdh = dhe;
1567d39a76e7Sxw mutex_exit(&chp->ch_dh_lck);
1568d39a76e7Sxw }
1569d39a76e7Sxw
1570d39a76e7Sxw cnt += tcnt;
1571d39a76e7Sxw #endif
1572d39a76e7Sxw while (cnt--) {
1573d39a76e7Sxw dhe = ch_get_dma_handle(chp);
1574d39a76e7Sxw if (dhe == NULL)
1575d39a76e7Sxw return;
1576d39a76e7Sxw mutex_enter(&chp->ch_dh_lck);
1577d39a76e7Sxw dhe->dhe_next = chp->ch_dh;
1578d39a76e7Sxw chp->ch_dh = dhe;
1579d39a76e7Sxw mutex_exit(&chp->ch_dh_lck);
1580d39a76e7Sxw }
1581d39a76e7Sxw }
1582d39a76e7Sxw
1583d39a76e7Sxw /*
1584d39a76e7Sxw * Write new values to the MTU table. Caller must validate that the new MTUs
1585d39a76e7Sxw * are in ascending order. params.mtus[] is initialized by init_mtus()
1586d39a76e7Sxw * called in t1_init_sw_modules().
1587d39a76e7Sxw */
1588d39a76e7Sxw #define MTUREG(idx) (A_TP_MTU_REG0 + (idx) * 4)
1589d39a76e7Sxw
1590d39a76e7Sxw static void
update_mtu_tab(ch_t * adapter)1591d39a76e7Sxw update_mtu_tab(ch_t *adapter)
1592d39a76e7Sxw {
1593d39a76e7Sxw int i;
1594d39a76e7Sxw
1595d39a76e7Sxw for (i = 0; i < NMTUS; ++i) {
1596d39a76e7Sxw int mtu = (unsigned int)adapter->params.mtus[i];
1597d39a76e7Sxw
1598d39a76e7Sxw t1_write_reg_4(adapter, MTUREG(i), mtu);
1599d39a76e7Sxw }
1600d39a76e7Sxw }
1601d39a76e7Sxw
1602d39a76e7Sxw static int
pe_change_mtu(ch_t * chp)1603d39a76e7Sxw pe_change_mtu(ch_t *chp)
1604d39a76e7Sxw {
1605d39a76e7Sxw struct cmac *mac = chp->port[0].mac;
1606d39a76e7Sxw int ret;
1607d39a76e7Sxw
1608d39a76e7Sxw if (!mac->ops->set_mtu) {
1609d39a76e7Sxw return (EOPNOTSUPP);
1610d39a76e7Sxw }
1611d39a76e7Sxw if (chp->ch_mtu < 68) {
1612d39a76e7Sxw return (EINVAL);
1613d39a76e7Sxw }
1614d39a76e7Sxw if (ret = mac->ops->set_mtu(mac, chp->ch_mtu)) {
1615d39a76e7Sxw return (ret);
1616d39a76e7Sxw }
1617d39a76e7Sxw
1618d39a76e7Sxw return (0);
1619d39a76e7Sxw }
1620d39a76e7Sxw
1621d39a76e7Sxw typedef struct fake_arp {
1622d39a76e7Sxw char fa_dst[6]; /* ethernet header */
1623d39a76e7Sxw char fa_src[6]; /* ethernet header */
1624d39a76e7Sxw ushort_t fa_typ; /* ethernet header */
1625d39a76e7Sxw
1626d39a76e7Sxw ushort_t fa_hrd; /* arp */
1627d39a76e7Sxw ushort_t fa_pro;
1628d39a76e7Sxw char fa_hln;
1629d39a76e7Sxw char fa_pln;
1630d39a76e7Sxw ushort_t fa_op;
1631d39a76e7Sxw char fa_src_mac[6];
1632d39a76e7Sxw uint_t fa_src_ip;
1633d39a76e7Sxw char fa_dst_mac[6];
1634d39a76e7Sxw char fa_dst_ip[4];
1635d39a76e7Sxw } fake_arp_t;
1636d39a76e7Sxw
1637d39a76e7Sxw /*
1638d39a76e7Sxw * PR2928 & PR3309
1639d39a76e7Sxw * construct packet in mblk and attach it to sge structure.
1640d39a76e7Sxw */
1641d39a76e7Sxw static int
pe_make_fake_arp(ch_t * chp,unsigned char * arpp)1642d39a76e7Sxw pe_make_fake_arp(ch_t *chp, unsigned char *arpp)
1643d39a76e7Sxw {
1644d39a76e7Sxw pesge *sge = chp->sge;
1645d39a76e7Sxw mblk_t *bp;
1646d39a76e7Sxw fake_arp_t *fap;
1647d39a76e7Sxw static char buf[6] = {0, 7, 0x43, 0, 0, 0};
1648d39a76e7Sxw struct cpl_tx_pkt *cpl;
1649d39a76e7Sxw
1650d39a76e7Sxw bp = allocb(sizeof (struct fake_arp) + SZ_CPL_TX_PKT, BPRI_HI);
1651d39a76e7Sxw if (bp == NULL) {
1652d39a76e7Sxw return (1);
1653d39a76e7Sxw }
1654d39a76e7Sxw bzero(bp->b_rptr, sizeof (struct fake_arp) + SZ_CPL_TX_PKT);
1655d39a76e7Sxw
1656d39a76e7Sxw /* fill in cpl header */
1657d39a76e7Sxw cpl = (struct cpl_tx_pkt *)bp->b_rptr;
1658d39a76e7Sxw cpl->opcode = CPL_TX_PKT;
1659d39a76e7Sxw cpl->iff = 0; /* XXX port 0 needs fixing with NEMO */
1660d39a76e7Sxw cpl->ip_csum_dis = 1; /* no IP header cksum */
1661d39a76e7Sxw cpl->l4_csum_dis = 1; /* no tcp/udp cksum */
1662d39a76e7Sxw cpl->vlan_valid = 0; /* no vlan */
1663d39a76e7Sxw
1664d39a76e7Sxw fap = (fake_arp_t *)&bp->b_rptr[SZ_CPL_TX_PKT];
1665d39a76e7Sxw
1666d39a76e7Sxw bcopy(arpp, fap, sizeof (*fap)); /* copy first arp to mblk */
1667d39a76e7Sxw
1668d39a76e7Sxw bcopy(buf, fap->fa_dst, 6); /* overwrite dst mac */
1669d39a76e7Sxw chp->ch_ip = fap->fa_src_ip; /* not used yet */
1670d39a76e7Sxw bcopy(buf, fap->fa_dst_mac, 6); /* overwrite dst mac */
1671d39a76e7Sxw
1672d39a76e7Sxw bp->b_wptr = bp->b_rptr + sizeof (struct fake_arp)+SZ_CPL_TX_PKT;
1673d39a76e7Sxw
1674d39a76e7Sxw sge_add_fake_arp(sge, (void *)bp);
1675d39a76e7Sxw
1676d39a76e7Sxw return (0);
1677d39a76e7Sxw }
1678d39a76e7Sxw
1679d39a76e7Sxw /*
1680d39a76e7Sxw * PR2928 & PR3309
1681d39a76e7Sxw * free the fake arp's mblk on sge structure.
1682d39a76e7Sxw */
1683d39a76e7Sxw void
pe_free_fake_arp(void * arp)1684d39a76e7Sxw pe_free_fake_arp(void *arp)
1685d39a76e7Sxw {
1686d39a76e7Sxw mblk_t *bp = (mblk_t *)(arp);
1687d39a76e7Sxw
1688d39a76e7Sxw freemsg(bp);
1689d39a76e7Sxw }
1690d39a76e7Sxw
1691d39a76e7Sxw /*
1692d39a76e7Sxw * extract ip address of nic from first outgoing arp.
1693d39a76e7Sxw */
1694d39a76e7Sxw static uint32_t
pe_get_ip(unsigned char * arpp)1695d39a76e7Sxw pe_get_ip(unsigned char *arpp)
1696d39a76e7Sxw {
1697d39a76e7Sxw fake_arp_t fap;
1698d39a76e7Sxw
1699d39a76e7Sxw /*
1700d39a76e7Sxw * first copy packet to buffer so we know
1701d39a76e7Sxw * it will be properly aligned.
1702d39a76e7Sxw */
1703d39a76e7Sxw bcopy(arpp, &fap, sizeof (fap)); /* copy first arp to buffer */
1704d39a76e7Sxw return (fap.fa_src_ip);
1705d39a76e7Sxw }
1706d39a76e7Sxw
1707d39a76e7Sxw /* ARGSUSED */
1708d39a76e7Sxw void
t1_os_link_changed(ch_t * obj,int port_id,int link_status,int speed,int duplex,int fc)1709d39a76e7Sxw t1_os_link_changed(ch_t *obj, int port_id, int link_status,
1710d39a76e7Sxw int speed, int duplex, int fc)
1711d39a76e7Sxw {
1712d39a76e7Sxw gld_mac_info_t *macinfo = obj->ch_macp;
1713d39a76e7Sxw if (link_status) {
1714d39a76e7Sxw gld_linkstate(macinfo, GLD_LINKSTATE_UP);
1715d39a76e7Sxw /*
1716d39a76e7Sxw * Link states should be reported to user
1717d39a76e7Sxw * whenever it changes
1718d39a76e7Sxw */
1719d39a76e7Sxw cmn_err(CE_NOTE, "%s: link is up", adapter_name(obj));
1720d39a76e7Sxw } else {
1721d39a76e7Sxw gld_linkstate(macinfo, GLD_LINKSTATE_DOWN);
1722d39a76e7Sxw /*
1723d39a76e7Sxw * Link states should be reported to user
1724d39a76e7Sxw * whenever it changes
1725d39a76e7Sxw */
1726d39a76e7Sxw cmn_err(CE_NOTE, "%s: link is down", adapter_name(obj));
1727d39a76e7Sxw }
1728d39a76e7Sxw }
1729