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 */
66struct 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
83struct toetool_reg {
84	uint32_t cmd;
85	uint32_t addr;
86	uint32_t val;
87};
88
89uint32_t
90t1_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
95void
96t1_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
101uint32_t
102t1_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
108int
109t1_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
115uint32_t
116t1_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
122int
123t1_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
129void *
130t1_os_malloc_wait_zero(size_t len)
131{
132	return (kmem_zalloc(len, KM_SLEEP));
133}
134
135void
136t1_os_free(void *adr, size_t len)
137{
138	kmem_free(adr, len);
139}
140
141int
142t1_num_of_ports(ch_t *obj)
143{
144	return (obj->config_data.num_of_ports);
145}
146
147/* ARGSUSED */
148int
149pe_os_mem_copy(ch_t *obj, void *dst, void *src, size_t len)
150{
151	bcopy(src, dst, len);
152	return (0);
153}
154
155int
156pe_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
169void
170pe_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
351bad:
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 */
365void *
366pe_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 */
389void
390pe_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
396void
397t1_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
407void
408CH_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
423void
424CH_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
439void
440CH_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
455u32
456le32_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 */
477void
478ch_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 */
493void
494ch_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 */
506void
507ch_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 */
519void
520ch_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