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