glue.c revision 7656:2621e50fdf4a
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