|
|
1.1 ! root 1: /* ! 2: * net-3-driver for the NI5210 card (i82586 Ethernet chip) ! 3: * ! 4: * This is an extension to the Linux operating system, and is covered by the ! 5: * same Gnu Public License that covers that work. ! 6: * ! 7: * Alphacode 0.62 (95/01/19) for Linux 1.1.82 (or later) ! 8: * Copyrights (c) 1994,1995 by M.Hipp ([email protected]) ! 9: * [feel free to mail ....] ! 10: * ! 11: * CAN YOU PLEASE REPORT ME YOUR PERFORMANCE EXPERIENCES !!. ! 12: * ! 13: * If you find a bug, please report me: ! 14: * The kernel panic output and any kmsg from the ni52 driver ! 15: * the ni5210-driver-version and the linux-kernel version ! 16: * how many shared memory (memsize) on the netcard, ! 17: * bootprom: yes/no, base_addr, mem_start ! 18: * maybe the ni5210-card revision and the i82586 version ! 19: * ! 20: * autoprobe for: base_addr: 0x300,0x280,0x360,0x320,0x340 ! 21: * mem_start: 0xc8000,0xd0000,0xd4000,0xd8000 (8K and 16K) ! 22: * ! 23: * sources: ! 24: * skeleton.c from Donald Becker ! 25: * ! 26: * I have also done a look in the following sources: (mail me if you need them) ! 27: * crynwr-packet-driver by Russ Nelson ! 28: * Garret A. Wollman's (fourth) i82586-driver for BSD ! 29: * (before getting an i82596 (yes 596 not 586) manual, the existing drivers helped ! 30: * me a lot to understand this tricky chip.) ! 31: * ! 32: * Known Problems: ! 33: * The internal sysbus seems to be slow. So we often lose packets because of ! 34: * overruns while receiving from a fast remote host. ! 35: * This can slow down TCP connections. Maybe the newer ni5210 cards are better. ! 36: * ! 37: * IMPORTANT NOTE: ! 38: * On fast networks, it's a (very) good idea to have 16K shared memory. With ! 39: * 8K, we can store only 4 receive frames, so it can (easily) happen that a remote ! 40: * machine 'overruns' our system. ! 41: * ! 42: * Known i82586 bugs (I'm sure, there are many more!): ! 43: * Running the NOP-mode, the i82586 sometimes seems to forget to report ! 44: * every xmit-interrupt until we restart the CU. ! 45: * Another MAJOR bug is, that the RU sometimes seems to ignore the EL-Bit ! 46: * in the RBD-Struct which indicates an end of the RBD queue. ! 47: * Instead, the RU fetches another (randomly selected and ! 48: * usually used) RBD and begins to fill it. (Maybe, this happens only if ! 49: * the last buffer from the previous RFD fits exact into the queue and ! 50: * the next RFD can't fetch an initial RBD. Anyone knows more? ) ! 51: */ ! 52: ! 53: /* ! 54: * 18.Nov.95: Mcast changes (AC). ! 55: * ! 56: * 19.Jan.95: verified (MH) ! 57: * ! 58: * 19.Sep.94: Added Multicast support (not tested yet) (MH) ! 59: * ! 60: * 18.Sep.94: Workaround for 'EL-Bug'. Removed flexible RBD-handling. ! 61: * Now, every RFD has exact one RBD. (MH) ! 62: * ! 63: * 14.Sep.94: added promiscuous mode, a few cleanups (MH) ! 64: * ! 65: * 19.Aug.94: changed request_irq() parameter (MH) ! 66: * ! 67: * 20.July.94: removed cleanup bugs, removed a 16K-mem-probe-bug (MH) ! 68: * ! 69: * 19.July.94: lotsa cleanups .. (MH) ! 70: * ! 71: * 17.July.94: some patches ... verified to run with 1.1.29 (MH) ! 72: * ! 73: * 4.July.94: patches for Linux 1.1.24 (MH) ! 74: * ! 75: * 26.March.94: patches for Linux 1.0 and iomem-auto-probe (MH) ! 76: * ! 77: * 30.Sep.93: Added nop-chain .. driver now runs with only one Xmit-Buff, too (MH) ! 78: * ! 79: * < 30.Sep.93: first versions ! 80: */ ! 81: ! 82: #include <linux/kernel.h> ! 83: #include <linux/sched.h> ! 84: #include <linux/string.h> ! 85: #include <linux/errno.h> ! 86: #include <linux/ioport.h> ! 87: #include <linux/malloc.h> ! 88: #include <linux/interrupt.h> ! 89: #include <linux/delay.h> ! 90: #include <asm/bitops.h> ! 91: #include <asm/io.h> ! 92: ! 93: #include <linux/netdevice.h> ! 94: #include <linux/etherdevice.h> ! 95: #include <linux/skbuff.h> ! 96: ! 97: #include "ni52.h" ! 98: ! 99: #define DEBUG /* debug on */ ! 100: #define SYSBUSVAL 1 /* 8 Bit */ ! 101: ! 102: #define ni_attn586() {outb(0,dev->base_addr+NI52_ATTENTION);} ! 103: #define ni_reset586() {outb(0,dev->base_addr+NI52_RESET);} ! 104: ! 105: #define make32(ptr16) (p->memtop + (short) (ptr16) ) ! 106: #define make24(ptr32) ((char *) (ptr32) - p->base) ! 107: #define make16(ptr32) ((unsigned short) ((unsigned long) (ptr32) - (unsigned long) p->memtop )) ! 108: ! 109: /******************* how to calculate the buffers ***************************** ! 110: ! 111: * IMPORTANT NOTE: if you configure only one NUM_XMIT_BUFFS, the driver works ! 112: * --------------- in a different (more stable?) mode. Only in this mode it's ! 113: * possible to configure the driver with 'NO_NOPCOMMANDS' ! 114: ! 115: sizeof(scp)=12; sizeof(scb)=16; sizeof(iscp)=8; ! 116: sizeof(scp)+sizeof(iscp)+sizeof(scb) = 36 = INIT ! 117: sizeof(rfd) = 24; sizeof(rbd) = 12; ! 118: sizeof(tbd) = 8; sizeof(transmit_cmd) = 16; ! 119: sizeof(nop_cmd) = 8; ! 120: ! 121: * if you don't know the driver, better do not change this values: */ ! 122: ! 123: #define RECV_BUFF_SIZE 1524 /* slightly oversized */ ! 124: #define XMIT_BUFF_SIZE 1524 /* slightly oversized */ ! 125: #define NUM_XMIT_BUFFS 1 /* config for both, 8K and 16K shmem */ ! 126: #define NUM_RECV_BUFFS_8 4 /* config for 8K shared mem */ ! 127: #define NUM_RECV_BUFFS_16 9 /* config for 16K shared mem */ ! 128: #define NO_NOPCOMMANDS /* only possible with NUM_XMIT_BUFFS=1 */ ! 129: ! 130: /**************************************************************************/ ! 131: ! 132: #define DELAY(x) {int i=jiffies; \ ! 133: if(loops_per_sec == 1) \ ! 134: while(i+(x)>jiffies); \ ! 135: else \ ! 136: __delay((loops_per_sec>>5)*x); \ ! 137: } ! 138: ! 139: /* a much shorter delay: */ ! 140: #define DELAY_16(); { __delay( (loops_per_sec>>16)+1 ); } ! 141: ! 142: /* wait for command with timeout: */ ! 143: #define WAIT_4_SCB_CMD() { int i; \ ! 144: for(i=0;i<1024;i++) { \ ! 145: if(!p->scb->cmd) break; \ ! 146: DELAY_16(); \ ! 147: if(i == 1023) { \ ! 148: printk("%s: scb_cmd timed out .. resetting i82586\n",dev->name); \ ! 149: ni_reset586(); } } } ! 150: ! 151: ! 152: #define NI52_TOTAL_SIZE 16 ! 153: #define NI52_ADDR0 0x02 ! 154: #define NI52_ADDR1 0x07 ! 155: #define NI52_ADDR2 0x01 ! 156: ! 157: #ifndef HAVE_PORTRESERVE ! 158: #define check_region(ioaddr, size) 0 ! 159: #define request_region(ioaddr, size,name) do ; while (0) ! 160: #endif ! 161: ! 162: static int ni52_probe1(struct device *dev,int ioaddr); ! 163: static void ni52_interrupt(int irq,struct pt_regs *reg_ptr); ! 164: static int ni52_open(struct device *dev); ! 165: static int ni52_close(struct device *dev); ! 166: static int ni52_send_packet(struct sk_buff *,struct device *); ! 167: static struct enet_statistics *ni52_get_stats(struct device *dev); ! 168: static void set_multicast_list(struct device *dev); ! 169: ! 170: /* helper-functions */ ! 171: static int init586(struct device *dev); ! 172: static int check586(struct device *dev,char *where,unsigned size); ! 173: static void alloc586(struct device *dev); ! 174: static void startrecv586(struct device *dev); ! 175: static void *alloc_rfa(struct device *dev,void *ptr); ! 176: static void ni52_rcv_int(struct device *dev); ! 177: static void ni52_xmt_int(struct device *dev); ! 178: static void ni52_rnr_int(struct device *dev); ! 179: ! 180: struct priv ! 181: { ! 182: struct enet_statistics stats; ! 183: unsigned long base; ! 184: char *memtop; ! 185: volatile struct rfd_struct *rfd_last,*rfd_top,*rfd_first; ! 186: volatile struct scp_struct *scp; /* volatile is important */ ! 187: volatile struct iscp_struct *iscp; /* volatile is important */ ! 188: volatile struct scb_struct *scb; /* volatile is important */ ! 189: volatile struct tbd_struct *xmit_buffs[NUM_XMIT_BUFFS]; ! 190: volatile struct transmit_cmd_struct *xmit_cmds[NUM_XMIT_BUFFS]; ! 191: #if (NUM_XMIT_BUFFS == 1) ! 192: volatile struct nop_cmd_struct *nop_cmds[2]; ! 193: #else ! 194: volatile struct nop_cmd_struct *nop_cmds[NUM_XMIT_BUFFS]; ! 195: #endif ! 196: volatile int nop_point,num_recv_buffs; ! 197: volatile char *xmit_cbuffs[NUM_XMIT_BUFFS]; ! 198: volatile int xmit_count,xmit_last; ! 199: }; ! 200: ! 201: ! 202: /********************************************** ! 203: * close device ! 204: */ ! 205: ! 206: static int ni52_close(struct device *dev) ! 207: { ! 208: free_irq(dev->irq); ! 209: irq2dev_map[dev->irq] = 0; ! 210: ! 211: ni_reset586(); /* the hard way to stop the receiver */ ! 212: ! 213: dev->start = 0; ! 214: dev->tbusy = 0; ! 215: ! 216: return 0; ! 217: } ! 218: ! 219: /********************************************** ! 220: * open device ! 221: */ ! 222: ! 223: static int ni52_open(struct device *dev) ! 224: { ! 225: alloc586(dev); ! 226: init586(dev); ! 227: startrecv586(dev); ! 228: ! 229: if(request_irq(dev->irq, &ni52_interrupt,0,"ni52")) ! 230: { ! 231: ni_reset586(); ! 232: return -EAGAIN; ! 233: } ! 234: irq2dev_map[dev->irq] = dev; ! 235: ! 236: dev->interrupt = 0; ! 237: dev->tbusy = 0; ! 238: dev->start = 1; ! 239: ! 240: return 0; /* most done by init */ ! 241: } ! 242: ! 243: /********************************************** ! 244: * Check to see if there's an 82586 out there. ! 245: */ ! 246: ! 247: static int check586(struct device *dev,char *where,unsigned size) ! 248: { ! 249: struct priv *p = (struct priv *) dev->priv; ! 250: char *iscp_addrs[2]; ! 251: int i; ! 252: ! 253: p->base = (unsigned long) where + size - 0x01000000; ! 254: p->memtop = where + size; ! 255: p->scp = (struct scp_struct *)(p->base + SCP_DEFAULT_ADDRESS); ! 256: memset((char *)p->scp,0, sizeof(struct scp_struct)); ! 257: p->scp->sysbus = SYSBUSVAL; /* 1 = 8Bit-Bus, 0 = 16 Bit */ ! 258: ! 259: iscp_addrs[0] = where; ! 260: iscp_addrs[1]= (char *) p->scp - sizeof(struct iscp_struct); ! 261: ! 262: for(i=0;i<2;i++) ! 263: { ! 264: p->iscp = (struct iscp_struct *) iscp_addrs[i]; ! 265: memset((char *)p->iscp,0, sizeof(struct iscp_struct)); ! 266: ! 267: p->scp->iscp = make24(p->iscp); ! 268: p->iscp->busy = 1; ! 269: ! 270: ni_reset586(); ! 271: ni_attn586(); ! 272: DELAY(2); /* wait a while... */ ! 273: ! 274: if(p->iscp->busy) /* i82586 clears 'busy' after successful init */ ! 275: return 0; ! 276: } ! 277: return 1; ! 278: } ! 279: ! 280: /****************************************************************** ! 281: * set iscp at the right place, called by ni52_probe1 and open586. ! 282: */ ! 283: ! 284: void alloc586(struct device *dev) ! 285: { ! 286: struct priv *p = (struct priv *) dev->priv; ! 287: ! 288: ni_reset586(); ! 289: DELAY(2); ! 290: ! 291: p->scp = (struct scp_struct *) (p->base + SCP_DEFAULT_ADDRESS); ! 292: p->scb = (struct scb_struct *) (dev->mem_start); ! 293: p->iscp = (struct iscp_struct *) ((char *)p->scp - sizeof(struct iscp_struct)); ! 294: ! 295: memset((char *) p->iscp,0,sizeof(struct iscp_struct)); ! 296: memset((char *) p->scp ,0,sizeof(struct scp_struct)); ! 297: ! 298: p->scp->iscp = make24(p->iscp); ! 299: p->scp->sysbus = SYSBUSVAL; ! 300: p->iscp->scb_offset = make16(p->scb); ! 301: ! 302: p->iscp->busy = 1; ! 303: ni_reset586(); ! 304: ni_attn586(); ! 305: ! 306: DELAY(2); ! 307: ! 308: if(p->iscp->busy) ! 309: printk("%s: Init-Problems (alloc).\n",dev->name); ! 310: ! 311: memset((char *)p->scb,0,sizeof(struct scb_struct)); ! 312: } ! 313: ! 314: /********************************************** ! 315: * probe the ni5210-card ! 316: */ ! 317: ! 318: int ni52_probe(struct device *dev) ! 319: { ! 320: int *port, ports[] = {0x300, 0x280, 0x360 , 0x320 , 0x340, 0}; ! 321: int base_addr = dev->base_addr; ! 322: ! 323: if (base_addr > 0x1ff) /* Check a single specified location. */ ! 324: if( (inb(base_addr+NI52_MAGIC1) == NI52_MAGICVAL1) && ! 325: (inb(base_addr+NI52_MAGIC2) == NI52_MAGICVAL2)) ! 326: return ni52_probe1(dev, base_addr); ! 327: else if (base_addr > 0) /* Don't probe at all. */ ! 328: return ENXIO; ! 329: ! 330: for (port = ports; *port; port++) { ! 331: int ioaddr = *port; ! 332: if (check_region(ioaddr, NI52_TOTAL_SIZE)) ! 333: continue; ! 334: if( !(inb(ioaddr+NI52_MAGIC1) == NI52_MAGICVAL1) || ! 335: !(inb(ioaddr+NI52_MAGIC2) == NI52_MAGICVAL2)) ! 336: continue; ! 337: ! 338: dev->base_addr = ioaddr; ! 339: if (ni52_probe1(dev, ioaddr) == 0) ! 340: return 0; ! 341: } ! 342: ! 343: dev->base_addr = base_addr; ! 344: return ENODEV; ! 345: } ! 346: ! 347: static int ni52_probe1(struct device *dev,int ioaddr) ! 348: { ! 349: long memaddrs[] = { 0xd0000,0xd2000,0xc8000,0xca000,0xd4000,0xd6000,0xd8000, 0 }; ! 350: int i,size; ! 351: ! 352: for(i=0;i<ETH_ALEN;i++) ! 353: dev->dev_addr[i] = inb(dev->base_addr+i); ! 354: ! 355: if(dev->dev_addr[0] != NI52_ADDR0 || dev->dev_addr[1] != NI52_ADDR1 ! 356: || dev->dev_addr[2] != NI52_ADDR2) ! 357: return ENODEV; ! 358: ! 359: printk("%s: Ni52 found at %#3lx, ",dev->name,dev->base_addr); ! 360: ! 361: request_region(ioaddr,NI52_TOTAL_SIZE,"ni52"); ! 362: ! 363: dev->priv = (void *) kmalloc(sizeof(struct priv),GFP_KERNEL); ! 364: /* warning: we don't free it on errors */ ! 365: if (dev->priv == NULL) ! 366: return -ENOMEM; ! 367: memset((char *) dev->priv,0,sizeof(struct priv)); ! 368: ! 369: /* ! 370: * check (or search) IO-Memory, 8K and 16K ! 371: */ ! 372: if(dev->mem_start != 0) /* no auto-mem-probe */ ! 373: { ! 374: size = 0x4000; /* check for 16K mem */ ! 375: if(!check586(dev,(char *) dev->mem_start,size)) { ! 376: size = 0x2000; /* check for 8K mem */ ! 377: if(!check586(dev,(char *) dev->mem_start,size)) { ! 378: printk("?memprobe, Can't find memory at 0x%lx!\n",dev->mem_start); ! 379: return ENODEV; ! 380: } ! 381: } ! 382: } ! 383: else ! 384: { ! 385: for(i=0;;i++) ! 386: { ! 387: if(!memaddrs[i]) { ! 388: printk("?memprobe, Can't find io-memory!\n"); ! 389: return ENODEV; ! 390: } ! 391: dev->mem_start = memaddrs[i]; ! 392: size = 0x2000; /* check for 8K mem */ ! 393: if(check586(dev,(char *)dev->mem_start,size)) /* 8K-check */ ! 394: break; ! 395: size = 0x4000; /* check for 16K mem */ ! 396: if(check586(dev,(char *)dev->mem_start,size)) /* 16K-check */ ! 397: break; ! 398: } ! 399: } ! 400: dev->mem_end = dev->mem_start + size; /* set mem_end showed by 'ifconfig' */ ! 401: ! 402: ((struct priv *) (dev->priv))->base = dev->mem_start + size - 0x01000000; ! 403: alloc586(dev); ! 404: ! 405: /* set number of receive-buffs according to memsize */ ! 406: if(size == 0x2000) ! 407: ((struct priv *) dev->priv)->num_recv_buffs = NUM_RECV_BUFFS_8; ! 408: else ! 409: ((struct priv *) dev->priv)->num_recv_buffs = NUM_RECV_BUFFS_16; ! 410: ! 411: printk("Memaddr: 0x%lx, Memsize: %d, ",dev->mem_start,size); ! 412: ! 413: if(dev->irq < 2) ! 414: { ! 415: autoirq_setup(0); ! 416: ni_reset586(); ! 417: ni_attn586(); ! 418: if(!(dev->irq = autoirq_report(2))) ! 419: { ! 420: printk("?autoirq, Failed to detect IRQ line!\n"); ! 421: return 1; ! 422: } ! 423: } ! 424: else if(dev->irq == 2) ! 425: dev->irq = 9; ! 426: ! 427: printk("IRQ %d.\n",dev->irq); ! 428: ! 429: dev->open = &ni52_open; ! 430: dev->stop = &ni52_close; ! 431: dev->get_stats = &ni52_get_stats; ! 432: dev->hard_start_xmit = &ni52_send_packet; ! 433: dev->set_multicast_list = &set_multicast_list; ! 434: ! 435: dev->if_port = 0; ! 436: ! 437: ether_setup(dev); ! 438: ! 439: dev->tbusy = 0; ! 440: dev->interrupt = 0; ! 441: dev->start = 0; ! 442: ! 443: return 0; ! 444: } ! 445: ! 446: /********************************************** ! 447: * init the chip (ni52-interrupt should be disabled?!) ! 448: * needs a correct 'allocated' memory ! 449: */ ! 450: ! 451: static int init586(struct device *dev) ! 452: { ! 453: void *ptr; ! 454: unsigned long s; ! 455: int i,result=0; ! 456: struct priv *p = (struct priv *) dev->priv; ! 457: volatile struct configure_cmd_struct *cfg_cmd; ! 458: volatile struct iasetup_cmd_struct *ias_cmd; ! 459: volatile struct tdr_cmd_struct *tdr_cmd; ! 460: volatile struct mcsetup_cmd_struct *mc_cmd; ! 461: struct dev_mc_list *dmi=dev->mc_list; ! 462: int num_addrs=dev->mc_count; ! 463: ! 464: ptr = (void *) ((char *)p->scb + sizeof(struct scb_struct)); ! 465: ! 466: cfg_cmd = (struct configure_cmd_struct *)ptr; /* configure-command */ ! 467: cfg_cmd->cmd_status = 0; ! 468: cfg_cmd->cmd_cmd = CMD_CONFIGURE | CMD_LAST; ! 469: cfg_cmd->cmd_link = 0xffff; ! 470: ! 471: cfg_cmd->byte_cnt = 0x0a; /* number of cfg bytes */ ! 472: cfg_cmd->fifo = 0x08; /* fifo-limit (8=tx:32/rx:64) */ ! 473: cfg_cmd->sav_bf = 0x40; /* hold or discard bad recv frames (bit 7) */ ! 474: cfg_cmd->adr_len = 0x2e; /* addr_len |!src_insert |pre-len |loopback */ ! 475: cfg_cmd->priority = 0x00; ! 476: cfg_cmd->ifs = 0x60; ! 477: cfg_cmd->time_low = 0x00; ! 478: cfg_cmd->time_high = 0xf2; ! 479: cfg_cmd->promisc = 0; ! 480: if(dev->flags&(IFF_ALLMULTI|IFF_PROMISC)) ! 481: { ! 482: cfg_cmd->promisc=1; ! 483: dev->flags|=IFF_PROMISC; ! 484: } ! 485: cfg_cmd->carr_coll = 0x00; ! 486: ! 487: p->scb->cbl_offset = make16(cfg_cmd); ! 488: ! 489: p->scb->cmd = CUC_START; /* cmd.-unit start */ ! 490: ni_attn586(); ! 491: ! 492: s = jiffies; /* warning: only active with interrupts on !! */ ! 493: while(!(cfg_cmd->cmd_status & STAT_COMPL)) ! 494: if(jiffies-s > 30) break; ! 495: ! 496: if((cfg_cmd->cmd_status & (STAT_OK|STAT_COMPL)) != (STAT_COMPL|STAT_OK)) ! 497: { ! 498: printk("%s (ni52): configure command failed: %x\n",dev->name,cfg_cmd->cmd_status); ! 499: return 1; ! 500: } ! 501: ! 502: /* ! 503: * individual address setup ! 504: */ ! 505: ias_cmd = (struct iasetup_cmd_struct *)ptr; ! 506: ! 507: ias_cmd->cmd_status = 0; ! 508: ias_cmd->cmd_cmd = CMD_IASETUP | CMD_LAST; ! 509: ias_cmd->cmd_link = 0xffff; ! 510: ! 511: memcpy((char *)&ias_cmd->iaddr,(char *) dev->dev_addr,ETH_ALEN); ! 512: ! 513: p->scb->cbl_offset = make16(ias_cmd); ! 514: ! 515: p->scb->cmd = CUC_START; /* cmd.-unit start */ ! 516: ni_attn586(); ! 517: ! 518: s = jiffies; ! 519: while(!(ias_cmd->cmd_status & STAT_COMPL)) ! 520: if(jiffies-s > 30) break; ! 521: ! 522: if((ias_cmd->cmd_status & (STAT_OK|STAT_COMPL)) != (STAT_OK|STAT_COMPL)) { ! 523: printk("%s (ni52): individual address setup command failed: %04x\n",dev->name,ias_cmd->cmd_status); ! 524: return 1; ! 525: } ! 526: ! 527: /* ! 528: * TDR, wire check .. e.g. no resistor e.t.c ! 529: */ ! 530: tdr_cmd = (struct tdr_cmd_struct *)ptr; ! 531: ! 532: tdr_cmd->cmd_status = 0; ! 533: tdr_cmd->cmd_cmd = CMD_TDR | CMD_LAST; ! 534: tdr_cmd->cmd_link = 0xffff; ! 535: tdr_cmd->status = 0; ! 536: ! 537: p->scb->cbl_offset = make16(tdr_cmd); ! 538: ! 539: p->scb->cmd = CUC_START; /* cmd.-unit start */ ! 540: ni_attn586(); ! 541: ! 542: s = jiffies; ! 543: while(!(tdr_cmd->cmd_status & STAT_COMPL)) ! 544: if(jiffies - s > 30) { ! 545: printk("%s: Problems while running the TDR.\n",dev->name); ! 546: result = 1; ! 547: } ! 548: ! 549: if(!result) ! 550: { ! 551: DELAY(2); /* wait for result */ ! 552: result = tdr_cmd->status; ! 553: ! 554: p->scb->cmd = p->scb->status & STAT_MASK; ! 555: ni_attn586(); /* ack the interrupts */ ! 556: ! 557: if(result & TDR_LNK_OK) ; ! 558: else if(result & TDR_XCVR_PRB) ! 559: printk("%s: TDR: Transceiver problem!\n",dev->name); ! 560: else if(result & TDR_ET_OPN) ! 561: printk("%s: TDR: No correct termination %d clocks away.\n",dev->name,result & TDR_TIMEMASK); ! 562: else if(result & TDR_ET_SRT) ! 563: { ! 564: if (result & TDR_TIMEMASK) /* time == 0 -> strange :-) */ ! 565: printk("%s: TDR: Detected a short circuit %d clocks away.\n",dev->name,result & TDR_TIMEMASK); ! 566: } ! 567: else ! 568: printk("%s: TDR: Unknown status %04x\n",dev->name,result); ! 569: } ! 570: ! 571: /* ! 572: * ack interrupts ! 573: */ ! 574: p->scb->cmd = p->scb->status & STAT_MASK; ! 575: ni_attn586(); ! 576: ! 577: /* ! 578: * alloc nop/xmit-cmds ! 579: */ ! 580: #if (NUM_XMIT_BUFFS == 1) ! 581: for(i=0;i<2;i++) ! 582: { ! 583: p->nop_cmds[i] = (struct nop_cmd_struct *)ptr; ! 584: p->nop_cmds[i]->cmd_cmd = CMD_NOP; ! 585: p->nop_cmds[i]->cmd_status = 0; ! 586: p->nop_cmds[i]->cmd_link = make16((p->nop_cmds[i])); ! 587: ptr = (char *) ptr + sizeof(struct nop_cmd_struct); ! 588: } ! 589: p->xmit_cmds[0] = (struct transmit_cmd_struct *)ptr; /* transmit cmd/buff 0 */ ! 590: ptr = (char *) ptr + sizeof(struct transmit_cmd_struct); ! 591: #else ! 592: for(i=0;i<NUM_XMIT_BUFFS;i++) ! 593: { ! 594: p->nop_cmds[i] = (struct nop_cmd_struct *)ptr; ! 595: p->nop_cmds[i]->cmd_cmd = CMD_NOP; ! 596: p->nop_cmds[i]->cmd_status = 0; ! 597: p->nop_cmds[i]->cmd_link = make16((p->nop_cmds[i])); ! 598: ptr = (char *) ptr + sizeof(struct nop_cmd_struct); ! 599: p->xmit_cmds[i] = (struct transmit_cmd_struct *)ptr; /*transmit cmd/buff 0*/ ! 600: ptr = (char *) ptr + sizeof(struct transmit_cmd_struct); ! 601: } ! 602: #endif ! 603: ! 604: ptr = alloc_rfa(dev,(void *)ptr); /* init receive-frame-area */ ! 605: ! 606: /* ! 607: * Multicast setup ! 608: */ ! 609: ! 610: if(dev->mc_count) ! 611: { /* I don't understand this: do we really need memory after the init? */ ! 612: int len = ((char *) p->iscp - (char *) ptr - 8) / 6; ! 613: if(len <= 0) ! 614: { ! 615: printk("%s: Ooooops, no memory for MC-Setup!\n",dev->name); ! 616: } ! 617: else ! 618: { ! 619: if(len < num_addrs) ! 620: { ! 621: /* BUG - should go ALLMULTI in this case */ ! 622: num_addrs = len; ! 623: printk("%s: Sorry, can only apply %d MC-Address(es).\n",dev->name,num_addrs); ! 624: } ! 625: mc_cmd = (struct mcsetup_cmd_struct *) ptr; ! 626: mc_cmd->cmd_status = 0; ! 627: mc_cmd->cmd_cmd = CMD_MCSETUP | CMD_LAST; ! 628: mc_cmd->cmd_link = 0xffff; ! 629: mc_cmd->mc_cnt = num_addrs * 6; ! 630: for(i=0;i<num_addrs;i++) ! 631: { ! 632: memcpy((char *) mc_cmd->mc_list[i], dmi->dmi_addr,6); ! 633: dmi=dmi->next; ! 634: } ! 635: p->scb->cbl_offset = make16(mc_cmd); ! 636: p->scb->cmd = CUC_START; ! 637: ni_attn586(); ! 638: s = jiffies; ! 639: while(!(mc_cmd->cmd_status & STAT_COMPL)) ! 640: if(jiffies - s > 30) ! 641: break; ! 642: if(!(mc_cmd->cmd_status & STAT_COMPL)) ! 643: printk("%s: Can't apply multicast-address-list.\n",dev->name); ! 644: } ! 645: } ! 646: ! 647: /* ! 648: * alloc xmit-buffs / init xmit_cmds ! 649: */ ! 650: for(i=0;i<NUM_XMIT_BUFFS;i++) ! 651: { ! 652: p->xmit_cbuffs[i] = (char *)ptr; /* char-buffs */ ! 653: ptr = (char *) ptr + XMIT_BUFF_SIZE; ! 654: p->xmit_buffs[i] = (struct tbd_struct *)ptr; /* TBD */ ! 655: ptr = (char *) ptr + sizeof(struct tbd_struct); ! 656: if((void *)ptr > (void *)p->iscp) ! 657: { ! 658: printk("%s: not enough shared-mem for your configuration!\n",dev->name); ! 659: return 1; ! 660: } ! 661: memset((char *)(p->xmit_cmds[i]) ,0, sizeof(struct transmit_cmd_struct)); ! 662: memset((char *)(p->xmit_buffs[i]),0, sizeof(struct tbd_struct)); ! 663: p->xmit_cmds[i]->cmd_status = STAT_COMPL; ! 664: p->xmit_cmds[i]->cmd_cmd = CMD_XMIT | CMD_INT; ! 665: p->xmit_cmds[i]->tbd_offset = make16((p->xmit_buffs[i])); ! 666: p->xmit_buffs[i]->next = 0xffff; ! 667: p->xmit_buffs[i]->buffer = make24((p->xmit_cbuffs[i])); ! 668: } ! 669: ! 670: p->xmit_count = 0; ! 671: p->xmit_last = 0; ! 672: #ifndef NO_NOPCOMMANDS ! 673: p->nop_point = 0; ! 674: #endif ! 675: ! 676: /* ! 677: * 'start transmitter' (nop-loop) ! 678: */ ! 679: #ifndef NO_NOPCOMMANDS ! 680: p->scb->cbl_offset = make16(p->nop_cmds[0]); ! 681: p->scb->cmd = CUC_START; ! 682: ni_attn586(); ! 683: WAIT_4_SCB_CMD(); ! 684: #else ! 685: p->xmit_cmds[0]->cmd_link = 0xffff; ! 686: p->xmit_cmds[0]->cmd_cmd = CMD_XMIT | CMD_LAST | CMD_INT; ! 687: #endif ! 688: ! 689: return 0; ! 690: } ! 691: ! 692: /****************************************************** ! 693: * This is a helper routine for ni52_rnr_int() and init586(). ! 694: * It sets up the Receive Frame Area (RFA). ! 695: */ ! 696: ! 697: static void *alloc_rfa(struct device *dev,void *ptr) ! 698: { ! 699: volatile struct rfd_struct *rfd = (struct rfd_struct *)ptr; ! 700: volatile struct rbd_struct *rbd; ! 701: int i; ! 702: struct priv *p = (struct priv *) dev->priv; ! 703: ! 704: memset((char *) rfd,0,sizeof(struct rfd_struct)*p->num_recv_buffs); ! 705: p->rfd_first = rfd; ! 706: ! 707: for(i = 0; i < p->num_recv_buffs; i++) ! 708: rfd[i].next = make16(rfd + (i+1) % p->num_recv_buffs); ! 709: rfd[p->num_recv_buffs-1].last = RFD_SUSP; /* RU suspend */ ! 710: ! 711: ptr = (void *) (rfd + p->num_recv_buffs); ! 712: ! 713: rbd = (struct rbd_struct *) ptr; ! 714: ptr = (void *) (rbd + p->num_recv_buffs); ! 715: ! 716: /* clr descriptors */ ! 717: memset((char *) rbd,0,sizeof(struct rbd_struct)*p->num_recv_buffs); ! 718: ! 719: for(i=0;i<p->num_recv_buffs;i++) ! 720: { ! 721: rbd[i].next = make16((rbd + (i+1) % p->num_recv_buffs)); ! 722: rbd[i].size = RECV_BUFF_SIZE; ! 723: rbd[i].buffer = make24(ptr); ! 724: ptr = (char *) ptr + RECV_BUFF_SIZE; ! 725: } ! 726: ! 727: p->rfd_top = p->rfd_first; ! 728: p->rfd_last = p->rfd_first + p->num_recv_buffs - 1; ! 729: ! 730: p->scb->rfa_offset = make16(p->rfd_first); ! 731: p->rfd_first->rbd_offset = make16(rbd); ! 732: ! 733: return ptr; ! 734: } ! 735: ! 736: ! 737: /************************************************** ! 738: * Interrupt Handler ... ! 739: */ ! 740: ! 741: static void ni52_interrupt(int irq,struct pt_regs *reg_ptr) ! 742: { ! 743: struct device *dev = (struct device *) irq2dev_map[irq]; ! 744: unsigned short stat; ! 745: struct priv *p; ! 746: ! 747: if (dev == NULL) { ! 748: printk ("ni52-interrupt: irq %d for unknown device.\n",(int) -(((struct pt_regs *)reg_ptr)->orig_eax+2)); ! 749: return; ! 750: } ! 751: p = (struct priv *) dev->priv; ! 752: ! 753: dev->interrupt = 1; ! 754: ! 755: while((stat=p->scb->status & STAT_MASK)) ! 756: { ! 757: p->scb->cmd = stat; ! 758: ni_attn586(); /* ack inter. */ ! 759: ! 760: if(stat & STAT_CX) /* command with I-bit set complete */ ! 761: ni52_xmt_int(dev); ! 762: ! 763: if(stat & STAT_FR) /* received a frame */ ! 764: ni52_rcv_int(dev); ! 765: ! 766: #ifndef NO_NOPCOMMANDS ! 767: if(stat & STAT_CNA) /* CU went 'not ready' */ ! 768: { ! 769: if(dev->start) ! 770: printk("%s: oops! CU has left active state. stat: %04x/%04x.\n",dev->name,(int) stat,(int) p->scb->status); ! 771: } ! 772: #endif ! 773: ! 774: if(stat & STAT_RNR) /* RU went 'not ready' */ ! 775: { ! 776: if(p->scb->status & RU_SUSPEND) /* special case: RU_SUSPEND */ ! 777: { ! 778: WAIT_4_SCB_CMD(); ! 779: p->scb->cmd = RUC_RESUME; ! 780: ni_attn586(); ! 781: } ! 782: else ! 783: { ! 784: printk("%s: Receiver-Unit went 'NOT READY': %04x/%04x.\n",dev->name,(int) stat,(int) p->scb->status); ! 785: ni52_rnr_int(dev); ! 786: } ! 787: } ! 788: WAIT_4_SCB_CMD(); /* wait for ack. (ni52_xmt_int can be faster than ack!!) */ ! 789: if(p->scb->cmd) /* timed out? */ ! 790: break; ! 791: } ! 792: ! 793: dev->interrupt = 0; ! 794: } ! 795: ! 796: /******************************************************* ! 797: * receive-interrupt ! 798: */ ! 799: ! 800: static void ni52_rcv_int(struct device *dev) ! 801: { ! 802: int status; ! 803: unsigned short totlen; ! 804: struct sk_buff *skb; ! 805: struct rbd_struct *rbd; ! 806: struct priv *p = (struct priv *) dev->priv; ! 807: ! 808: for(;(status = p->rfd_top->status) & STAT_COMPL;) ! 809: { ! 810: rbd = (struct rbd_struct *) make32(p->rfd_top->rbd_offset); ! 811: ! 812: if(status & STAT_OK) /* frame received without error? */ ! 813: { ! 814: if( (totlen = rbd->status) & RBD_LAST) /* the first and the last buffer? */ ! 815: { ! 816: totlen &= RBD_MASK; /* length of this frame */ ! 817: rbd->status = 0; ! 818: skb = (struct sk_buff *) dev_alloc_skb(totlen+2); ! 819: if(skb != NULL) ! 820: { ! 821: skb->dev = dev; ! 822: skb_reserve(skb,2); /* 16 byte alignment */ ! 823: memcpy(skb_put(skb,totlen),(char *) p->base+(unsigned long) rbd->buffer, totlen); ! 824: skb->protocol=eth_type_trans(skb,dev); ! 825: netif_rx(skb); ! 826: p->stats.rx_packets++; ! 827: } ! 828: else ! 829: p->stats.rx_dropped++; ! 830: } ! 831: else ! 832: { ! 833: printk("%s: received oversized frame.\n",dev->name); ! 834: p->stats.rx_dropped++; ! 835: } ! 836: } ! 837: else /* frame !(ok), only with 'save-bad-frames' */ ! 838: { ! 839: printk("%s: oops! rfd-error-status: %04x\n",dev->name,status); ! 840: p->stats.rx_errors++; ! 841: } ! 842: p->rfd_top->status = 0; ! 843: p->rfd_top->last = RFD_SUSP; ! 844: p->rfd_last->last = 0; /* delete RU_SUSP */ ! 845: p->rfd_last = p->rfd_top; ! 846: p->rfd_top = (struct rfd_struct *) make32(p->rfd_top->next); /* step to next RFD */ ! 847: } ! 848: } ! 849: ! 850: /********************************************************** ! 851: * handle 'Receiver went not ready'. ! 852: */ ! 853: ! 854: static void ni52_rnr_int(struct device *dev) ! 855: { ! 856: struct priv *p = (struct priv *) dev->priv; ! 857: ! 858: p->stats.rx_errors++; ! 859: ! 860: WAIT_4_SCB_CMD(); /* wait for the last cmd */ ! 861: p->scb->cmd = RUC_ABORT; /* usually the RU is in the 'no resource'-state .. abort it now. */ ! 862: ni_attn586(); ! 863: WAIT_4_SCB_CMD(); /* wait for accept cmd. */ ! 864: ! 865: alloc_rfa(dev,(char *)p->rfd_first); ! 866: startrecv586(dev); /* restart RU */ ! 867: ! 868: printk("%s: Receive-Unit restarted. Status: %04x\n",dev->name,p->scb->status); ! 869: ! 870: } ! 871: ! 872: /********************************************************** ! 873: * handle xmit - interrupt ! 874: */ ! 875: ! 876: static void ni52_xmt_int(struct device *dev) ! 877: { ! 878: int status; ! 879: struct priv *p = (struct priv *) dev->priv; ! 880: ! 881: status = p->xmit_cmds[p->xmit_last]->cmd_status; ! 882: if(!(status & STAT_COMPL)) ! 883: printk("%s: strange .. xmit-int without a 'COMPLETE'\n",dev->name); ! 884: ! 885: if(status & STAT_OK) ! 886: { ! 887: p->stats.tx_packets++; ! 888: p->stats.collisions += (status & TCMD_MAXCOLLMASK); ! 889: } ! 890: else ! 891: { ! 892: p->stats.tx_errors++; ! 893: if(status & TCMD_LATECOLL) { ! 894: printk("%s: late collision detected.\n",dev->name); ! 895: p->stats.collisions++; ! 896: } ! 897: else if(status & TCMD_NOCARRIER) { ! 898: p->stats.tx_carrier_errors++; ! 899: printk("%s: no carrier detected.\n",dev->name); ! 900: } ! 901: else if(status & TCMD_LOSTCTS) ! 902: printk("%s: loss of CTS detected.\n",dev->name); ! 903: else if(status & TCMD_UNDERRUN) { ! 904: p->stats.tx_fifo_errors++; ! 905: printk("%s: DMA underrun detected.\n",dev->name); ! 906: } ! 907: else if(status & TCMD_MAXCOLL) { ! 908: printk("%s: Max. collisions exceeded.\n",dev->name); ! 909: p->stats.collisions += 16; ! 910: } ! 911: } ! 912: ! 913: #if (NUM_XMIT_BUFFS != 1) ! 914: if( (++p->xmit_last) == NUM_XMIT_BUFFS) ! 915: p->xmit_last = 0; ! 916: #endif ! 917: ! 918: dev->tbusy = 0; ! 919: mark_bh(NET_BH); ! 920: } ! 921: ! 922: /*********************************************************** ! 923: * (re)start the receiver ! 924: */ ! 925: ! 926: static void startrecv586(struct device *dev) ! 927: { ! 928: struct priv *p = (struct priv *) dev->priv; ! 929: ! 930: p->scb->rfa_offset = make16(p->rfd_first); ! 931: p->scb->cmd = RUC_START; ! 932: ni_attn586(); /* start cmd. */ ! 933: WAIT_4_SCB_CMD(); /* wait for accept cmd. (no timeout!!) */ ! 934: } ! 935: ! 936: /****************************************************** ! 937: * send frame ! 938: */ ! 939: ! 940: static int ni52_send_packet(struct sk_buff *skb, struct device *dev) ! 941: { ! 942: int len,i; ! 943: #ifndef NO_NOPCOMMANDS ! 944: int next_nop; ! 945: #endif ! 946: struct priv *p = (struct priv *) dev->priv; ! 947: ! 948: if(dev->tbusy) ! 949: { ! 950: int tickssofar = jiffies - dev->trans_start; ! 951: if (tickssofar < 5) ! 952: return 1; ! 953: ! 954: if(p->scb->status & CU_ACTIVE) /* COMMAND-UNIT active? */ ! 955: { ! 956: dev->tbusy = 0; ! 957: #ifdef DEBUG ! 958: printk("%s: strange ... timeout with CU active?!?\n",dev->name); ! 959: printk("%s: X0: %04x N0: %04x N1: %04x %d\n",dev->name,(int)p->xmit_cmds[0]->cmd_status,(int)p->nop_cmds[0]->cmd_status,(int)p->nop_cmds[1]->cmd_status,(int)p->nop_point); ! 960: #endif ! 961: p->scb->cmd = CUC_ABORT; ! 962: ni_attn586(); ! 963: WAIT_4_SCB_CMD(); ! 964: p->scb->cbl_offset = make16(p->nop_cmds[p->nop_point]); ! 965: p->scb->cmd = CUC_START; ! 966: ni_attn586(); ! 967: WAIT_4_SCB_CMD(); ! 968: dev->trans_start = jiffies; ! 969: return 0; ! 970: } ! 971: else ! 972: { ! 973: #ifdef DEBUG ! 974: printk("%s: xmitter timed out, try to restart! stat: %04x\n",dev->name,p->scb->status); ! 975: printk("%s: command-stats: %04x %04x\n",dev->name,p->xmit_cmds[0]->cmd_status,p->xmit_cmds[1]->cmd_status); ! 976: #endif ! 977: ni52_close(dev); ! 978: ni52_open(dev); ! 979: } ! 980: dev->trans_start = jiffies; ! 981: return 0; ! 982: } ! 983: ! 984: if(skb == NULL) ! 985: { ! 986: dev_tint(dev); ! 987: return 0; ! 988: } ! 989: ! 990: if (skb->len <= 0) ! 991: return 0; ! 992: if(skb->len > XMIT_BUFF_SIZE) ! 993: { ! 994: printk("%s: Sorry, max. framelength is %d bytes. The length of your frame is %ld bytes.\n",dev->name,XMIT_BUFF_SIZE,skb->len); ! 995: return 0; ! 996: } ! 997: ! 998: if (set_bit(0, (void*)&dev->tbusy) != 0) ! 999: printk("%s: Transmitter access conflict.\n", dev->name); ! 1000: else ! 1001: { ! 1002: memcpy((char *)p->xmit_cbuffs[p->xmit_count],(char *)(skb->data),skb->len); ! 1003: len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN; ! 1004: ! 1005: #if (NUM_XMIT_BUFFS == 1) ! 1006: # ifdef NO_NOPCOMMANDS ! 1007: p->xmit_buffs[0]->size = TBD_LAST | len; ! 1008: for(i=0;i<16;i++) ! 1009: { ! 1010: p->scb->cbl_offset = make16(p->xmit_cmds[0]); ! 1011: p->scb->cmd = CUC_START; ! 1012: p->xmit_cmds[0]->cmd_status = 0; ! 1013: ! 1014: ni_attn586(); ! 1015: dev->trans_start = jiffies; ! 1016: if(!i) ! 1017: dev_kfree_skb(skb,FREE_WRITE); ! 1018: WAIT_4_SCB_CMD(); ! 1019: if( (p->scb->status & CU_ACTIVE)) /* test it, because CU sometimes doesn't start immediately */ ! 1020: break; ! 1021: if(p->xmit_cmds[0]->cmd_status) ! 1022: break; ! 1023: if(i==15) ! 1024: printk("%s: Can't start transmit-command.\n",dev->name); ! 1025: } ! 1026: # else ! 1027: next_nop = (p->nop_point + 1) & 0x1; ! 1028: p->xmit_buffs[0]->size = TBD_LAST | len; ! 1029: ! 1030: p->xmit_cmds[0]->cmd_link = p->nop_cmds[next_nop]->cmd_link ! 1031: = make16((p->nop_cmds[next_nop])); ! 1032: p->xmit_cmds[0]->cmd_status = p->nop_cmds[next_nop]->cmd_status = 0; ! 1033: ! 1034: p->nop_cmds[p->nop_point]->cmd_link = make16((p->xmit_cmds[0])); ! 1035: dev->trans_start = jiffies; ! 1036: p->nop_point = next_nop; ! 1037: dev_kfree_skb(skb,FREE_WRITE); ! 1038: # endif ! 1039: #else ! 1040: p->xmit_buffs[p->xmit_count]->size = TBD_LAST | len; ! 1041: if( (next_nop = p->xmit_count + 1) == NUM_XMIT_BUFFS ) ! 1042: next_nop = 0; ! 1043: ! 1044: p->xmit_cmds[p->xmit_count]->cmd_status = 0; ! 1045: p->xmit_cmds[p->xmit_count]->cmd_link = p->nop_cmds[next_nop]->cmd_link ! 1046: = make16((p->nop_cmds[next_nop])); ! 1047: p->nop_cmds[next_nop]->cmd_status = 0; ! 1048: ! 1049: p->nop_cmds[p->xmit_count]->cmd_link = make16((p->xmit_cmds[p->xmit_count])); ! 1050: dev->trans_start = jiffies; ! 1051: p->xmit_count = next_nop; ! 1052: ! 1053: cli(); ! 1054: if(p->xmit_count != p->xmit_last) ! 1055: dev->tbusy = 0; ! 1056: sti(); ! 1057: dev_kfree_skb(skb,FREE_WRITE); ! 1058: #endif ! 1059: } ! 1060: return 0; ! 1061: } ! 1062: ! 1063: /******************************************* ! 1064: * Someone wanna have the statistics ! 1065: */ ! 1066: ! 1067: static struct enet_statistics *ni52_get_stats(struct device *dev) ! 1068: { ! 1069: struct priv *p = (struct priv *) dev->priv; ! 1070: unsigned short crc,aln,rsc,ovrn; ! 1071: ! 1072: crc = p->scb->crc_errs; /* get error-statistic from the ni82586 */ ! 1073: p->scb->crc_errs -= crc; ! 1074: aln = p->scb->aln_errs; ! 1075: p->scb->aln_errs -= aln; ! 1076: rsc = p->scb->rsc_errs; ! 1077: p->scb->rsc_errs -= rsc; ! 1078: ovrn = p->scb->ovrn_errs; ! 1079: p->scb->ovrn_errs -= ovrn; ! 1080: ! 1081: p->stats.rx_crc_errors += crc; ! 1082: p->stats.rx_fifo_errors += ovrn; ! 1083: p->stats.rx_frame_errors += aln; ! 1084: p->stats.rx_dropped += rsc; ! 1085: ! 1086: return &p->stats; ! 1087: } ! 1088: ! 1089: /******************************************************** ! 1090: * Set MC list .. ! 1091: */ ! 1092: ! 1093: static void set_multicast_list(struct device *dev) ! 1094: { ! 1095: if(!dev->start) ! 1096: { ! 1097: printk("%s: Can't apply promiscuous/multicastmode to a not running interface.\n",dev->name); ! 1098: return; ! 1099: } ! 1100: ! 1101: dev->start = 0; ! 1102: alloc586(dev); ! 1103: init586(dev); ! 1104: startrecv586(dev); ! 1105: dev->start = 1; ! 1106: } ! 1107: ! 1108: /* ! 1109: * END: linux/drivers/net/ni52.c ! 1110: */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.