xref: /titanic_44/usr/src/uts/common/io/chxge/glue.c (revision 193974072f41a843678abf5f61979c748687e66b)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*
28  * This file is part of the Chelsio T1 Ethernet driver.
29  *
30  * Copyright (C) 2003-2005 Chelsio Communications.  All rights reserved.
31  */
32 
33 /*
34  * Solaris support routines for common code part of
35  * Chelsio PCI Ethernet Driver.
36  */
37 
38 #include <sys/types.h>
39 #include <sys/conf.h>
40 #include <sys/stropts.h>
41 #include <sys/stream.h>
42 #include <sys/strlog.h>
43 #include <sys/kmem.h>
44 #include <sys/stat.h>
45 #include <sys/kstat.h>
46 #include <sys/modctl.h>
47 #include <sys/errno.h>
48 #include <sys/varargs.h>
49 #include <sys/ddi.h>
50 #include <sys/sunddi.h>
51 #include <sys/dlpi.h>
52 #include <sys/ethernet.h>
53 #include <sys/strsun.h>
54 #include "ostypes.h"
55 #undef OFFSET
56 #include "common.h"
57 #include <sys/gld.h>
58 #include "oschtoe.h"
59 #include "ch.h"			/* Chelsio Driver specific parameters */
60 #include "sge.h"
61 #include "regs.h"
62 
63 /*
64  * Device specific.
65  */
66 struct pe_reg {
67 	uint32_t cmd;
68 	uint32_t addr;
69 	union {
70 		uint32_t v32;
71 		uint64_t v64;
72 	}vv;
73 	union {
74 		uint32_t m32;
75 		uint64_t m64;
76 	}mm;
77 };
78 #define	pe_reg_val vv.v32
79 #define	pe_opt_val vv.v64
80 #define	pe_mask32  mm.m32
81 #define	pe_mask64  mm.m64
82 
83 struct toetool_reg {
84 	uint32_t cmd;
85 	uint32_t addr;
86 	uint32_t val;
87 };
88 
89 uint32_t
t1_read_reg_4(ch_t * obj,uint32_t reg_val)90 t1_read_reg_4(ch_t *obj, uint32_t reg_val)
91 {
92 	return (ddi_get32(obj->ch_hbar0, (uint32_t *)(obj->ch_bar0 + reg_val)));
93 }
94 
95 void
t1_write_reg_4(ch_t * obj,uint32_t reg_val,uint32_t write_val)96 t1_write_reg_4(ch_t *obj, uint32_t reg_val, uint32_t write_val)
97 {
98 	ddi_put32(obj->ch_hbar0, (uint32_t *)(obj->ch_bar0+reg_val), write_val);
99 }
100 
101 uint32_t
t1_os_pci_read_config_2(ch_t * obj,uint32_t reg,uint16_t * val)102 t1_os_pci_read_config_2(ch_t *obj, uint32_t reg, uint16_t *val)
103 {
104 	*val = pci_config_get16(obj->ch_hpci, reg);
105 	return (0);
106 }
107 
108 int
t1_os_pci_write_config_2(ch_t * obj,uint32_t reg,uint16_t val)109 t1_os_pci_write_config_2(ch_t *obj, uint32_t reg, uint16_t val)
110 {
111 	pci_config_put16(obj->ch_hpci, reg, val);
112 	return (0);
113 }
114 
115 uint32_t
t1_os_pci_read_config_4(ch_t * obj,uint32_t reg,uint32_t * val)116 t1_os_pci_read_config_4(ch_t *obj, uint32_t reg, uint32_t *val)
117 {
118 	*val = pci_config_get32(obj->ch_hpci, reg);
119 	return (0);
120 }
121 
122 int
t1_os_pci_write_config_4(ch_t * obj,uint32_t reg,uint32_t val)123 t1_os_pci_write_config_4(ch_t *obj, uint32_t reg, uint32_t val)
124 {
125 	pci_config_put32(obj->ch_hpci, reg, val);
126 	return (0);
127 }
128 
129 void *
t1_os_malloc_wait_zero(size_t len)130 t1_os_malloc_wait_zero(size_t len)
131 {
132 	return (kmem_zalloc(len, KM_SLEEP));
133 }
134 
135 void
t1_os_free(void * adr,size_t len)136 t1_os_free(void *adr, size_t len)
137 {
138 	kmem_free(adr, len);
139 }
140 
141 int
t1_num_of_ports(ch_t * obj)142 t1_num_of_ports(ch_t *obj)
143 {
144 	return (obj->config_data.num_of_ports);
145 }
146 
147 /* ARGSUSED */
148 int
pe_os_mem_copy(ch_t * obj,void * dst,void * src,size_t len)149 pe_os_mem_copy(ch_t *obj, void *dst, void *src, size_t len)
150 {
151 	bcopy(src, dst, len);
152 	return (0);
153 }
154 
155 int
pe_is_ring_buffer_enabled(ch_t * obj)156 pe_is_ring_buffer_enabled(ch_t *obj)
157 {
158 	return (obj->config & CFGMD_RINGB);
159 }
160 
161 #define	PE_READ_REG  _IOR('i', 0xAB, 0x18)
162 #define	PE_WRITE_REG _IOW('i', 0xAB, 0x18)
163 #define	PE_READ_PCI  _IOR('i', 0xAC, 0x18)
164 #define	PE_WRITE_PCI _IOW('i', 0xAC, 0x18)
165 #define	PE_READ_INTR _IOR('i', 0xAD, 0x20)
166 #define	TOETOOL_GETTPI _IOR('i', 0xAE, 0xc)
167 #define	TOETOOL_SETTPI _IOW('i', 0xAE, 0xc)
168 
169 void
pe_ioctl(ch_t * chp,queue_t * q,mblk_t * mp)170 pe_ioctl(ch_t *chp, queue_t *q, mblk_t *mp)
171 {
172 	struct iocblk *iocp;
173 	mblk_t *dmp;
174 	struct pe_reg *pe;
175 	struct toetool_reg *te;
176 	uint32_t reg;
177 	struct sge_intr_counts *se, *sep;
178 
179 	iocp = (struct iocblk *)mp->b_rptr;
180 
181 	/* don't support TRASPARENT ioctls */
182 	if (iocp->ioc_count == TRANSPARENT) {
183 		iocp->ioc_error = ENOTTY;
184 		goto bad;
185 	}
186 
187 	/*
188 	 * sanity checks. There should be a M_DATA mblk following
189 	 * the initial M_IOCTL mblk
190 	 */
191 	if ((dmp = mp->b_cont) == NULL) {
192 		iocp->ioc_error = ENOTTY;
193 		goto bad;
194 	}
195 
196 	if (dmp->b_datap->db_type != M_DATA) {
197 		iocp->ioc_error = ENOTTY;
198 		goto bad;
199 	}
200 
201 	pe = (struct pe_reg *)dmp->b_rptr;
202 	se = (struct sge_intr_counts *)dmp->b_rptr;
203 	te = (struct toetool_reg *)dmp->b_rptr;
204 
205 	/* now process the ioctl */
206 	switch (iocp->ioc_cmd) {
207 	case PE_READ_REG:
208 
209 		if ((dmp->b_wptr - dmp->b_rptr) != sizeof (*pe)) {
210 			iocp->ioc_error = ENOTTY;
211 			goto bad;
212 		}
213 
214 		/* protect against bad addr values */
215 		pe->addr &= (uint32_t)~3;
216 
217 		pe->pe_mask32 = 0xFFFFFFFF;
218 
219 		if (pe->addr == 0x950)
220 			pe->pe_reg_val = reg = t1_sge_get_ptimeout(chp);
221 		else
222 			pe->pe_reg_val = reg = t1_read_reg_4(chp, pe->addr);
223 
224 		mp->b_datap->db_type = M_IOCACK;
225 		iocp->ioc_count = sizeof (*pe);
226 
227 		break;
228 
229 	case PE_WRITE_REG:
230 
231 		if ((dmp->b_wptr - dmp->b_rptr) != sizeof (*pe)) {
232 			iocp->ioc_error = ENOTTY;
233 			goto bad;
234 		}
235 
236 		if (pe->addr == 0x950)
237 			t1_sge_set_ptimeout(chp, pe->pe_reg_val);
238 		else {
239 			if (pe->pe_mask32 != 0xffffffff) {
240 				reg = t1_read_reg_4(chp, pe->addr);
241 				pe->pe_reg_val |= (reg & ~pe->pe_mask32);
242 			}
243 
244 			t1_write_reg_4(chp, pe->addr,  pe->pe_reg_val);
245 		}
246 
247 		if (mp->b_cont)
248 			freemsg(mp->b_cont);
249 		mp->b_cont = NULL;
250 		mp->b_datap->db_type = M_IOCACK;
251 		break;
252 
253 	case PE_READ_PCI:
254 
255 		if ((dmp->b_wptr - dmp->b_rptr) != sizeof (*pe)) {
256 			iocp->ioc_error = ENOTTY;
257 			goto bad;
258 		}
259 
260 		/* protect against bad addr values */
261 		pe->addr &= (uint32_t)~3;
262 
263 		pe->pe_mask32 = 0xFFFFFFFF;
264 		pe->pe_reg_val = reg = pci_config_get32(chp->ch_hpci, pe->addr);
265 		mp->b_datap->db_type = M_IOCACK;
266 		iocp->ioc_count = sizeof (*pe);
267 
268 		break;
269 
270 	case PE_WRITE_PCI:
271 
272 		if ((dmp->b_wptr - dmp->b_rptr) != sizeof (*pe)) {
273 			iocp->ioc_error = ENOTTY;
274 			goto bad;
275 		}
276 
277 		if (pe->pe_mask32 != 0xffffffff) {
278 			reg = pci_config_get32(chp->ch_hpci, pe->addr);
279 			pe->pe_reg_val |= (reg & ~pe->pe_mask32);
280 		}
281 
282 		pci_config_put32(chp->ch_hpci, pe->addr,  pe->pe_reg_val);
283 
284 		if (mp->b_cont)
285 			freemsg(mp->b_cont);
286 		mp->b_cont = NULL;
287 		mp->b_datap->db_type = M_IOCACK;
288 		break;
289 
290 	case PE_READ_INTR:
291 
292 		if ((dmp->b_wptr - dmp->b_rptr) != sizeof (*se)) {
293 			iocp->ioc_error = ENOTTY;
294 			goto bad;
295 		}
296 
297 		sep = sge_get_stat(chp->sge);
298 		bcopy(sep, se, sizeof (*se));
299 		mp->b_datap->db_type = M_IOCACK;
300 		iocp->ioc_count = sizeof (*se);
301 		break;
302 
303 	case TOETOOL_GETTPI:
304 
305 		if ((dmp->b_wptr - dmp->b_rptr) != sizeof (*te)) {
306 			iocp->ioc_error = ENOTTY;
307 			goto bad;
308 		}
309 
310 		/* protect against bad addr values */
311 		if ((te->addr & 3) != 0) {
312 			iocp->ioc_error = ENOTTY;
313 			goto bad;
314 		}
315 
316 		(void) t1_tpi_read(chp, te->addr, &te->val);
317 		mp->b_datap->db_type = M_IOCACK;
318 		iocp->ioc_count = sizeof (*te);
319 
320 		break;
321 
322 	case TOETOOL_SETTPI:
323 
324 		if ((dmp->b_wptr - dmp->b_rptr) != sizeof (*te)) {
325 			iocp->ioc_error = ENOTTY;
326 			goto bad;
327 		}
328 
329 		/* protect against bad addr values */
330 		if ((te->addr & 3) != 0) {
331 			iocp->ioc_error = ENOTTY;
332 			goto bad;
333 		}
334 
335 		(void) t1_tpi_write(chp, te->addr, te->val);
336 
337 		mp->b_datap->db_type = M_IOCACK;
338 		iocp->ioc_count = sizeof (*te);
339 
340 		break;
341 
342 	default:
343 		iocp->ioc_error = ENOTTY;
344 		goto bad;
345 	}
346 
347 	qreply(q, mp);
348 
349 	return;
350 
351 bad:
352 	if (mp->b_cont)
353 		freemsg(mp->b_cont);
354 	mp->b_cont = NULL;
355 	mp->b_datap->db_type = M_IOCNAK;
356 
357 	qreply(q, mp);
358 }
359 
360 /*
361  * Can't wait for memory here, since we have to use the Solaris dma
362  * mechanisms to determine the physical address.
363  * flg is either 0 (read) or DMA_OUT (write).
364  */
365 void *
pe_os_malloc_contig_wait_zero(ch_t * chp,size_t len,uint64_t * dma_addr,ulong_t * dh,ulong_t * ah,uint32_t flg)366 pe_os_malloc_contig_wait_zero(ch_t *chp, size_t len, uint64_t *dma_addr,
367 	ulong_t *dh, ulong_t *ah, uint32_t flg)
368 {
369 	void *mem = NULL;
370 	uint64_t pa;
371 
372 	/*
373 	 * byte swap, consistant mapping & 4k aligned
374 	 */
375 	mem = ch_alloc_dma_mem(chp, 1, DMA_4KALN|flg, len, &pa, dh, ah);
376 	if (mem == NULL) {
377 		return (0);
378 	}
379 
380 	if (dma_addr)
381 		*dma_addr = pa;
382 
383 	bzero(mem, len);
384 
385 	return ((void *)mem);
386 }
387 
388 /* ARGSUSED */
389 void
pe_os_free_contig(ch_t * obj,size_t len,void * addr,uint64_t dma_addr,ulong_t dh,ulong_t ah)390 pe_os_free_contig(ch_t *obj, size_t len, void *addr, uint64_t dma_addr,
391 			ulong_t dh, ulong_t ah)
392 {
393 	ch_free_dma_mem(dh, ah);
394 }
395 
396 void
t1_fatal_err(ch_t * adapter)397 t1_fatal_err(ch_t *adapter)
398 {
399 	if (adapter->ch_flags & PEINITDONE) {
400 		(void) sge_stop(adapter->sge);
401 		t1_interrupts_disable(adapter);
402 	}
403 	CH_ALERT("%s: encountered fatal error, operation suspended\n",
404 	    adapter_name(adapter));
405 }
406 
407 void
CH_ALERT(const char * fmt,...)408 CH_ALERT(const char *fmt, ...)
409 {
410 	va_list	ap;
411 	char	buf[128];
412 
413 	/* format buf using fmt and arguments contained in ap */
414 
415 	va_start(ap, fmt);
416 	(void) vsprintf(buf, fmt, ap);
417 	va_end(ap);
418 
419 	/* pass formatted string to cmn_err(9F) */
420 	cmn_err(CE_WARN, "%s", buf);
421 }
422 
423 void
CH_WARN(const char * fmt,...)424 CH_WARN(const char *fmt, ...)
425 {
426 	va_list	ap;
427 	char	buf[128];
428 
429 	/* format buf using fmt and arguments contained in ap */
430 
431 	va_start(ap, fmt);
432 	(void) vsprintf(buf, fmt, ap);
433 	va_end(ap);
434 
435 	/* pass formatted string to cmn_err(9F) */
436 	cmn_err(CE_WARN, "%s", buf);
437 }
438 
439 void
CH_ERR(const char * fmt,...)440 CH_ERR(const char *fmt, ...)
441 {
442 	va_list	ap;
443 	char	buf[128];
444 
445 	/* format buf using fmt and arguments contained in ap */
446 
447 	va_start(ap, fmt);
448 	(void) vsprintf(buf, fmt, ap);
449 	va_end(ap);
450 
451 	/* pass formatted string to cmn_err(9F) */
452 	cmn_err(CE_WARN, "%s", buf);
453 }
454 
455 u32
le32_to_cpu(u32 data)456 le32_to_cpu(u32 data)
457 {
458 #if BYTE_ORDER == BIG_ENDIAN
459 	uint8_t *in, t;
460 	in = (uint8_t *)&data;
461 	t = in[0];
462 	in[0] = in[3];
463 	in[3] = t;
464 	t = in[1];
465 	in[1] = in[2];
466 	in[2] = t;
467 #endif
468 	return (data);
469 }
470 
471 /*
472  * This function initializes a polling routine, Poll_func
473  * which will be polled ever N Microsecond, where N is
474  * provided in the cyclic start routine.
475  */
476 /* ARGSUSED */
477 void
ch_init_cyclic(void * adapter,p_ch_cyclic_t cyclic,void (* poll_func)(void *),void * arg)478 ch_init_cyclic(void *adapter, p_ch_cyclic_t cyclic,
479 		void (*poll_func)(void *), void *arg)
480 {
481 	cyclic->func = poll_func;
482 	cyclic->arg = arg;
483 	cyclic->timer = 0;
484 }
485 
486 /*
487  * Cyclic function which provides a periodic polling
488  * capability to Solaris. The poll function provided by
489  * the 'ch_init_cyclic' function is called from this
490  * here, and this routine launches a new one-shot
491  * timer to bring it back in some period later.
492  */
493 void
ch_cyclic(p_ch_cyclic_t cyclic)494 ch_cyclic(p_ch_cyclic_t cyclic)
495 {
496 	if (cyclic->timer != 0) {
497 		cyclic->func(cyclic->arg);
498 		cyclic->timer = timeout((void(*)(void  *))ch_cyclic,
499 		    (void *)cyclic, cyclic->period);
500 	}
501 }
502 
503 /*
504  * The 'ch_start_cyclic' starts the polling.
505  */
506 void
ch_start_cyclic(p_ch_cyclic_t cyclic,unsigned long period)507 ch_start_cyclic(p_ch_cyclic_t cyclic, unsigned long period)
508 {
509 	cyclic->period = drv_usectohz(period * 1000);
510 	if (cyclic->timer == 0) {
511 		cyclic->timer = timeout((void(*)(void  *))ch_cyclic,
512 		    (void *)cyclic, cyclic->period);
513 	}
514 }
515 
516 /*
517  * The 'ch_stop_cyclic' stops the polling.
518  */
519 void
ch_stop_cyclic(p_ch_cyclic_t cyclic)520 ch_stop_cyclic(p_ch_cyclic_t cyclic)
521 {
522 	timeout_id_t timer;
523 	clock_t value;
524 
525 	do {
526 		timer = cyclic->timer;
527 		cyclic->timer = 0;
528 		value = untimeout(timer);
529 		if (value == 0)
530 			drv_usecwait(drv_hztousec(2 * cyclic->period));
531 	} while ((timer != 0) && (value == 0));
532 }
533