[1094cf0d] | 1 | /* |
---|
[5a820308] | 2 | * RTEMS driver for TULIP based Ethernet Controller |
---|
[1094cf0d] | 3 | * |
---|
[5a820308] | 4 | * Copyright (C) 1999 Emmanuel Raguet. raguet@crf.canon.fr |
---|
| 5 | * |
---|
| 6 | * The license and distribution terms for this file may be |
---|
| 7 | * found in found in the file LICENSE in this distribution or at |
---|
[94365d9] | 8 | * http://www.rtems.com/license/LICENSE. |
---|
[5a820308] | 9 | * |
---|
| 10 | * $Id$ |
---|
[df49c60] | 11 | * |
---|
| 12 | * ------------------------------------------------------------------------ |
---|
| 13 | * [22.05.2000,StWi/CWA] added support for the DEC/Intel 21143 chip |
---|
| 14 | * |
---|
| 15 | * The 21143 support is (for now) only available for the __i386 target, |
---|
| 16 | * because that's the only testing platform I have. It should (to my best |
---|
| 17 | * knowledge) work in the same way for the "__PPC" target, but someone |
---|
| 18 | * should test this first before it's put into the code. Thanks go to |
---|
| 19 | * Andrew Klossner who provided the vital information about the |
---|
| 20 | * Intel 21143 chip. |
---|
| 21 | * (FWIW: I tested this driver using a Kingston KNE100TX with 21143PD chip) |
---|
| 22 | * |
---|
| 23 | * The driver will automatically detect whether there is a 21140 or 21143 |
---|
| 24 | * network card in the system and activate support accordingly. It will |
---|
| 25 | * look for the 21140 first. If the 21140 is not found the driver will |
---|
| 26 | * look for the 21143. |
---|
| 27 | * ------------------------------------------------------------------------ |
---|
[01b6ca9] | 28 | * |
---|
| 29 | * 2003-03-13, Greg Menke, gregory.menke@gsfc.nasa.gov |
---|
| 30 | * |
---|
| 31 | * Added support for up to 8 units (which is an arbitrary limit now), |
---|
| 32 | * consolidating their support into a single pair of rx/tx daemons and a |
---|
| 33 | * single ISR for all vectors servicing the DEC units. The driver now |
---|
| 34 | * simply uses whatever INTERRUPT_LINE the card supplies, requiring it |
---|
| 35 | * be configured either by the boot monitor or bspstart() hackery. |
---|
| 36 | * Tested on a MCP750 PPC based system with 2 DEC21140 boards. |
---|
| 37 | * |
---|
| 38 | * Also fixed a few bugs related to board configuration, start and stop. |
---|
| 39 | * |
---|
[1094cf0d] | 40 | */ |
---|
| 41 | |
---|
[a1efd7a] | 42 | #include <rtems.h> |
---|
| 43 | |
---|
| 44 | /* |
---|
| 45 | * This driver only supports architectures with the new style |
---|
| 46 | * exception processing. The following checks try to keep this |
---|
| 47 | * from being compiled on systems which can't support this driver. |
---|
| 48 | */ |
---|
| 49 | |
---|
[f7b46db] | 50 | #if defined(__i386__) |
---|
[df49c60] | 51 | #define DEC21140_SUPPORTED |
---|
[a1efd7a] | 52 | #endif |
---|
| 53 | |
---|
[01b6ca9] | 54 | #if defined(__PPC__) && (defined(mpc604) || defined(mpc750) || defined(mpc603e)) |
---|
[df49c60] | 55 | #define DEC21140_SUPPORTED |
---|
[a1efd7a] | 56 | #endif |
---|
| 57 | |
---|
| 58 | #if defined(DEC21140_SUPPORTED) |
---|
[1094cf0d] | 59 | #include <bsp.h> |
---|
[f7b46db] | 60 | #if defined(__i386__) |
---|
[1094cf0d] | 61 | #include <pcibios.h> |
---|
[5a820308] | 62 | #endif |
---|
[7c4ef9c] | 63 | #if defined(__PPC__) |
---|
[5a820308] | 64 | #include <bsp/pci.h> |
---|
| 65 | #include <libcpu/byteorder.h> |
---|
| 66 | #include <libcpu/io.h> |
---|
| 67 | #endif |
---|
[1094cf0d] | 68 | |
---|
| 69 | #include <stdlib.h> |
---|
| 70 | #include <stdio.h> |
---|
| 71 | #include <stdarg.h> |
---|
[01b6ca9] | 72 | #include <string.h> |
---|
[593bc32] | 73 | #include <errno.h> |
---|
[1094cf0d] | 74 | #include <rtems/error.h> |
---|
[c22aeb4] | 75 | #include <rtems/bspIo.h> |
---|
[1094cf0d] | 76 | #include <rtems/rtems_bsdnet.h> |
---|
| 77 | |
---|
| 78 | #include <sys/param.h> |
---|
| 79 | #include <sys/mbuf.h> |
---|
| 80 | |
---|
| 81 | #include <sys/socket.h> |
---|
| 82 | #include <sys/sockio.h> |
---|
| 83 | #include <net/if.h> |
---|
| 84 | #include <netinet/in.h> |
---|
| 85 | #include <netinet/if_ether.h> |
---|
[a3d3d9a] | 86 | |
---|
[f7b46db] | 87 | #if defined(__i386__) |
---|
[1094cf0d] | 88 | #include <irq.h> |
---|
[5a820308] | 89 | #endif |
---|
[51b9899] | 90 | #if defined(__PPC__) |
---|
[5a820308] | 91 | #include <bsp/irq.h> |
---|
| 92 | #endif |
---|
[1094cf0d] | 93 | |
---|
| 94 | #ifdef malloc |
---|
| 95 | #undef malloc |
---|
| 96 | #endif |
---|
| 97 | #ifdef free |
---|
[a3d3d9a] | 98 | #undef free |
---|
[1094cf0d] | 99 | #endif |
---|
| 100 | |
---|
[5a820308] | 101 | #define DEC_DEBUG |
---|
| 102 | |
---|
[df49c60] | 103 | /* note: the 21143 isn't really a DEC, it's an Intel chip */ |
---|
[5a820308] | 104 | #define PCI_INVALID_VENDORDEVICEID 0xffffffff |
---|
[01b6ca9] | 105 | #define PCI_VENDOR_ID_DEC 0x1011 |
---|
| 106 | #define PCI_DEVICE_ID_DEC_21140 0x0009 |
---|
| 107 | #define PCI_DEVICE_ID_DEC_21143 0x0019 |
---|
| 108 | |
---|
| 109 | #define DRIVER_PREFIX "dc" |
---|
[1094cf0d] | 110 | |
---|
[96e62937] | 111 | #define IO_MASK 0x3 |
---|
[1094cf0d] | 112 | #define MEM_MASK 0xF |
---|
| 113 | |
---|
| 114 | /* command and status registers, 32-bit access, only if IO-ACCESS */ |
---|
| 115 | #define ioCSR0 0x00 /* bus mode register */ |
---|
| 116 | #define ioCSR1 0x08 /* transmit poll demand */ |
---|
| 117 | #define ioCSR2 0x10 /* receive poll demand */ |
---|
| 118 | #define ioCSR3 0x18 /* receive list base address */ |
---|
| 119 | #define ioCSR4 0x20 /* transmit list base address */ |
---|
| 120 | #define ioCSR5 0x28 /* status register */ |
---|
| 121 | #define ioCSR6 0x30 /* operation mode register */ |
---|
| 122 | #define ioCSR7 0x38 /* interrupt mask register */ |
---|
| 123 | #define ioCSR8 0x40 /* missed frame counter */ |
---|
| 124 | #define ioCSR9 0x48 /* Ethernet ROM register */ |
---|
| 125 | #define ioCSR10 0x50 /* reserved */ |
---|
| 126 | #define ioCSR11 0x58 /* full-duplex register */ |
---|
| 127 | #define ioCSR12 0x60 /* SIA status register */ |
---|
| 128 | #define ioCSR13 0x68 |
---|
| 129 | #define ioCSR14 0x70 |
---|
| 130 | #define ioCSR15 0x78 /* SIA general register */ |
---|
| 131 | |
---|
| 132 | /* command and status registers, 32-bit access, only if MEMORY-ACCESS */ |
---|
| 133 | #define memCSR0 0x00 /* bus mode register */ |
---|
| 134 | #define memCSR1 0x02 /* transmit poll demand */ |
---|
| 135 | #define memCSR2 0x04 /* receive poll demand */ |
---|
| 136 | #define memCSR3 0x06 /* receive list base address */ |
---|
| 137 | #define memCSR4 0x08 /* transmit list base address */ |
---|
| 138 | #define memCSR5 0x0A /* status register */ |
---|
| 139 | #define memCSR6 0x0C /* operation mode register */ |
---|
| 140 | #define memCSR7 0x0E /* interrupt mask register */ |
---|
| 141 | #define memCSR8 0x10 /* missed frame counter */ |
---|
| 142 | #define memCSR9 0x12 /* Ethernet ROM register */ |
---|
| 143 | #define memCSR10 0x14 /* reserved */ |
---|
| 144 | #define memCSR11 0x16 /* full-duplex register */ |
---|
| 145 | #define memCSR12 0x18 /* SIA status register */ |
---|
| 146 | #define memCSR13 0x1A |
---|
| 147 | #define memCSR14 0x1C |
---|
| 148 | #define memCSR15 0x1E /* SIA general register */ |
---|
| 149 | |
---|
| 150 | #define DEC_REGISTER_SIZE 0x100 /* to reserve virtual memory */ |
---|
| 151 | |
---|
[01b6ca9] | 152 | |
---|
| 153 | |
---|
| 154 | |
---|
[1094cf0d] | 155 | #define RESET_CHIP 0x00000001 |
---|
[51b9899] | 156 | #if defined(__PPC__) |
---|
[5a820308] | 157 | #define CSR0_MODE 0x0030e002 /* 01b08000 */ |
---|
| 158 | #else |
---|
| 159 | #define CSR0_MODE 0x0020e002 /* 01b08000 */ |
---|
| 160 | #endif |
---|
[1094cf0d] | 161 | #define ROM_ADDRESS 0x00004800 |
---|
[a3d3d9a] | 162 | #define CSR6_INIT 0x022cc000 /* 022c0000 020c0000 */ |
---|
| 163 | #define CSR6_TX 0x00002000 |
---|
| 164 | #define CSR6_TXRX 0x00002002 |
---|
[5a820308] | 165 | #define IT_SETUP 0x000100c0 /* 000100e0 */ |
---|
[a3d3d9a] | 166 | #define CLEAR_IT 0xFFFFFFFF |
---|
| 167 | #define NO_IT 0x00000000 |
---|
[1094cf0d] | 168 | |
---|
[01b6ca9] | 169 | |
---|
[1094cf0d] | 170 | |
---|
| 171 | /* message descriptor entry */ |
---|
| 172 | struct MD { |
---|
[5a820308] | 173 | /* used by hardware */ |
---|
[ee4f57d] | 174 | volatile uint32_t status; |
---|
| 175 | volatile uint32_t counts; |
---|
[a3d3d9a] | 176 | volatile uint32_t buf1, buf2; |
---|
[5a820308] | 177 | /* used by software */ |
---|
| 178 | volatile struct mbuf *m; |
---|
| 179 | volatile struct MD *next; |
---|
[01b6ca9] | 180 | } __attribute__ ((packed)); |
---|
| 181 | |
---|
| 182 | |
---|
| 183 | |
---|
| 184 | |
---|
| 185 | /* |
---|
| 186 | ** These buffers allocated for each unit, so ensure |
---|
| 187 | ** |
---|
| 188 | ** rtems_bsdnet_config.mbuf_bytecount |
---|
| 189 | ** rtems_bsdnet_config.mbuf_cluster_bytecount |
---|
| 190 | ** |
---|
| 191 | ** are adequately sized to provide enough clusters and mbufs for all the |
---|
| 192 | ** units. The default bsdnet configuration is sufficient for one dec |
---|
| 193 | ** unit, but will be nearing exhaustion with 2 or more. Although a |
---|
| 194 | ** little expensive in memory, the following configuration should |
---|
| 195 | ** eliminate all mbuf/cluster issues; |
---|
| 196 | ** |
---|
| 197 | ** rtems_bsdnet_config.mbuf_bytecount = 128*1024; |
---|
| 198 | ** rtems_bsdnet_config.mbuf_cluster_bytecount = 256*1024; |
---|
| 199 | */ |
---|
| 200 | |
---|
| 201 | #define NRXBUFS 16 /* number of receive buffers */ |
---|
| 202 | #define NTXBUFS 16 /* number of transmit buffers */ |
---|
| 203 | |
---|
[1094cf0d] | 204 | |
---|
| 205 | /* |
---|
[01b6ca9] | 206 | * Number of DEC boards supported by this driver |
---|
[1094cf0d] | 207 | */ |
---|
[01b6ca9] | 208 | #define NDECDRIVER 8 |
---|
| 209 | |
---|
[1094cf0d] | 210 | |
---|
| 211 | /* |
---|
| 212 | * Receive buffer size -- Allow for a full ethernet packet including CRC |
---|
| 213 | */ |
---|
[66a8c6f] | 214 | #define RBUF_SIZE 1536 |
---|
[1094cf0d] | 215 | |
---|
[01b6ca9] | 216 | #define ET_MINLEN 60 /* minimum message length */ |
---|
[1094cf0d] | 217 | |
---|
| 218 | |
---|
| 219 | /* |
---|
[01b6ca9] | 220 | ** Events, one per unit. The event is sent to the rx task from the isr |
---|
| 221 | ** or from the stack to the tx task whenever a unit needs service. The |
---|
| 222 | ** rx/tx tasks identify the requesting unit(s) by their particular |
---|
| 223 | ** events so only requesting units are serviced. |
---|
| 224 | */ |
---|
| 225 | |
---|
[a3d3d9a] | 226 | static rtems_event_set unit_signals[NDECDRIVER]= { RTEMS_EVENT_1, |
---|
[01b6ca9] | 227 | RTEMS_EVENT_2, |
---|
[a3d3d9a] | 228 | RTEMS_EVENT_3, |
---|
[01b6ca9] | 229 | RTEMS_EVENT_4, |
---|
[a3d3d9a] | 230 | RTEMS_EVENT_5, |
---|
[01b6ca9] | 231 | RTEMS_EVENT_6, |
---|
[a3d3d9a] | 232 | RTEMS_EVENT_7, |
---|
[01b6ca9] | 233 | RTEMS_EVENT_8 }; |
---|
| 234 | |
---|
[1094cf0d] | 235 | |
---|
[51b9899] | 236 | #if defined(__PPC__) |
---|
[a191b28] | 237 | #define phys_to_bus(address) ((unsigned int)((address)) + PCI_DRAM_OFFSET) |
---|
| 238 | #define bus_to_phys(address) ((unsigned int)((address)) - PCI_DRAM_OFFSET) |
---|
[5a820308] | 239 | #define CPU_CACHE_ALIGNMENT_FOR_BUFFER PPC_CACHE_ALIGNMENT |
---|
| 240 | #else |
---|
[95f5adb] | 241 | extern void Wait_X_ms( unsigned int timeToWait ); |
---|
[bdb2899] | 242 | #define phys_to_bus(address) ((unsigned int) ((address))) |
---|
| 243 | #define bus_to_phys(address) ((unsigned int) ((address))) |
---|
[a191b28] | 244 | #define rtems_bsp_delay_in_bus_cycles(cycle) Wait_X_ms( cycle/100 ) |
---|
[5a820308] | 245 | #define CPU_CACHE_ALIGNMENT_FOR_BUFFER PG_SIZE |
---|
| 246 | |
---|
[1402d56a] | 247 | static inline void st_le32(volatile uint32_t *addr, uint32_t value) |
---|
[5a820308] | 248 | { |
---|
| 249 | *(addr)=value ; |
---|
| 250 | } |
---|
| 251 | |
---|
[1402d56a] | 252 | static inline uint32_t ld_le32(volatile uint32_t *addr) |
---|
[5a820308] | 253 | { |
---|
| 254 | return(*addr); |
---|
| 255 | } |
---|
| 256 | |
---|
| 257 | #endif |
---|
| 258 | |
---|
[1094cf0d] | 259 | #if (MCLBYTES < RBUF_SIZE) |
---|
| 260 | # error "Driver must have MCLBYTES > RBUF_SIZE" |
---|
| 261 | #endif |
---|
| 262 | |
---|
[01b6ca9] | 263 | |
---|
| 264 | |
---|
| 265 | |
---|
| 266 | |
---|
[1094cf0d] | 267 | /* |
---|
| 268 | * Per-device data |
---|
| 269 | */ |
---|
[01b6ca9] | 270 | struct dec21140_softc { |
---|
[5a820308] | 271 | |
---|
[01b6ca9] | 272 | struct arpcom arpcom; |
---|
[5a820308] | 273 | |
---|
[01b6ca9] | 274 | rtems_irq_connect_data irqInfo; |
---|
| 275 | rtems_event_set ioevent; |
---|
[1094cf0d] | 276 | |
---|
[96e62937] | 277 | int numRxbuffers, numTxbuffers; |
---|
| 278 | |
---|
[01b6ca9] | 279 | volatile struct MD *MDbase; |
---|
| 280 | volatile struct MD *nextRxMD; |
---|
| 281 | volatile unsigned char *bufferBase; |
---|
| 282 | int acceptBroadcast; |
---|
[a3d3d9a] | 283 | |
---|
[01b6ca9] | 284 | volatile struct MD *TxMD; |
---|
| 285 | volatile struct MD *SentTxMD; |
---|
| 286 | int PendingTxCount; |
---|
| 287 | int TxSuspended; |
---|
| 288 | |
---|
| 289 | unsigned int port; |
---|
| 290 | volatile unsigned int *base; |
---|
| 291 | |
---|
| 292 | /* |
---|
| 293 | * Statistics |
---|
| 294 | */ |
---|
| 295 | unsigned long rxInterrupts; |
---|
| 296 | unsigned long rxNotFirst; |
---|
| 297 | unsigned long rxNotLast; |
---|
| 298 | unsigned long rxGiant; |
---|
| 299 | unsigned long rxNonOctet; |
---|
| 300 | unsigned long rxRunt; |
---|
| 301 | unsigned long rxBadCRC; |
---|
| 302 | unsigned long rxOverrun; |
---|
| 303 | unsigned long rxCollision; |
---|
[a3d3d9a] | 304 | |
---|
[01b6ca9] | 305 | unsigned long txInterrupts; |
---|
| 306 | unsigned long txDeferred; |
---|
| 307 | unsigned long txHeartbeat; |
---|
| 308 | unsigned long txLateCollision; |
---|
| 309 | unsigned long txRetryLimit; |
---|
| 310 | unsigned long txUnderrun; |
---|
| 311 | unsigned long txLostCarrier; |
---|
| 312 | unsigned long txRawWait; |
---|
[1094cf0d] | 313 | }; |
---|
| 314 | |
---|
| 315 | static struct dec21140_softc dec21140_softc[NDECDRIVER]; |
---|
[01b6ca9] | 316 | static rtems_id rxDaemonTid; |
---|
| 317 | static rtems_id txDaemonTid; |
---|
| 318 | |
---|
| 319 | |
---|
| 320 | |
---|
| 321 | |
---|
| 322 | |
---|
| 323 | |
---|
| 324 | |
---|
| 325 | |
---|
| 326 | |
---|
| 327 | |
---|
| 328 | |
---|
| 329 | |
---|
[1094cf0d] | 330 | |
---|
| 331 | |
---|
| 332 | |
---|
| 333 | |
---|
| 334 | |
---|
| 335 | /* |
---|
| 336 | * This routine reads a word (16 bits) from the serial EEPROM. |
---|
| 337 | */ |
---|
| 338 | /* EEPROM_Ctrl bits. */ |
---|
| 339 | #define EE_SHIFT_CLK 0x02 /* EEPROM shift clock. */ |
---|
| 340 | #define EE_CS 0x01 /* EEPROM chip select. */ |
---|
| 341 | #define EE_DATA_WRITE 0x04 /* EEPROM chip data in. */ |
---|
| 342 | #define EE_WRITE_0 0x01 |
---|
| 343 | #define EE_WRITE_1 0x05 |
---|
| 344 | #define EE_DATA_READ 0x08 /* EEPROM chip data out. */ |
---|
| 345 | #define EE_ENB (0x4800 | EE_CS) |
---|
| 346 | |
---|
| 347 | /* The EEPROM commands include the alway-set leading bit. */ |
---|
| 348 | #define EE_WRITE_CMD (5 << 6) |
---|
| 349 | #define EE_READ_CMD (6 << 6) |
---|
| 350 | #define EE_ERASE_CMD (7 << 6) |
---|
| 351 | |
---|
[5a820308] | 352 | static int eeget16(volatile unsigned int *ioaddr, int location) |
---|
[1094cf0d] | 353 | { |
---|
[01b6ca9] | 354 | int i; |
---|
| 355 | unsigned short retval = 0; |
---|
| 356 | int read_cmd = location | EE_READ_CMD; |
---|
[a3d3d9a] | 357 | |
---|
[01b6ca9] | 358 | st_le32(ioaddr, EE_ENB & ~EE_CS); |
---|
| 359 | st_le32(ioaddr, EE_ENB); |
---|
[a3d3d9a] | 360 | |
---|
[01b6ca9] | 361 | /* Shift the read command bits out. */ |
---|
| 362 | for (i = 10; i >= 0; i--) { |
---|
| 363 | short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0; |
---|
| 364 | st_le32(ioaddr, EE_ENB | dataval); |
---|
| 365 | rtems_bsp_delay_in_bus_cycles(200); |
---|
| 366 | st_le32(ioaddr, EE_ENB | dataval | EE_SHIFT_CLK); |
---|
| 367 | rtems_bsp_delay_in_bus_cycles(200); |
---|
| 368 | st_le32(ioaddr, EE_ENB | dataval); /* Finish EEPROM a clock tick. */ |
---|
| 369 | rtems_bsp_delay_in_bus_cycles(200); |
---|
| 370 | } |
---|
| 371 | st_le32(ioaddr, EE_ENB); |
---|
[a3d3d9a] | 372 | |
---|
[01b6ca9] | 373 | for (i = 16; i > 0; i--) { |
---|
| 374 | st_le32(ioaddr, EE_ENB | EE_SHIFT_CLK); |
---|
| 375 | rtems_bsp_delay_in_bus_cycles(200); |
---|
| 376 | retval = (retval << 1) | ((ld_le32(ioaddr) & EE_DATA_READ) ? 1 : 0); |
---|
| 377 | st_le32(ioaddr, EE_ENB); |
---|
| 378 | rtems_bsp_delay_in_bus_cycles(200); |
---|
| 379 | } |
---|
| 380 | |
---|
| 381 | /* Terminate the EEPROM access. */ |
---|
| 382 | st_le32(ioaddr, EE_ENB & ~EE_CS); |
---|
| 383 | return ( ((retval<<8)&0xff00) | ((retval>>8)&0xff) ); |
---|
| 384 | } |
---|
| 385 | |
---|
| 386 | |
---|
| 387 | |
---|
| 388 | |
---|
| 389 | |
---|
| 390 | |
---|
| 391 | |
---|
| 392 | |
---|
| 393 | |
---|
| 394 | |
---|
| 395 | |
---|
| 396 | |
---|
| 397 | |
---|
| 398 | |
---|
| 399 | |
---|
| 400 | |
---|
| 401 | |
---|
| 402 | |
---|
| 403 | |
---|
| 404 | |
---|
| 405 | |
---|
| 406 | |
---|
| 407 | static void no_op(const rtems_irq_connect_data* irq) |
---|
| 408 | { |
---|
| 409 | return; |
---|
| 410 | } |
---|
| 411 | |
---|
| 412 | |
---|
| 413 | |
---|
| 414 | |
---|
| 415 | static int dec21140IsOn(const rtems_irq_connect_data* irq) |
---|
| 416 | { |
---|
| 417 | return BSP_irq_enabled_at_i8259s (irq->name); |
---|
[1094cf0d] | 418 | } |
---|
| 419 | |
---|
[01b6ca9] | 420 | |
---|
| 421 | |
---|
| 422 | |
---|
[1094cf0d] | 423 | /* |
---|
[01b6ca9] | 424 | * DEC21140 interrupt handler |
---|
[1094cf0d] | 425 | */ |
---|
[01b6ca9] | 426 | static rtems_isr |
---|
| 427 | dec21140Enet_interrupt_handler ( struct dec21140_softc *sc ) |
---|
[1094cf0d] | 428 | { |
---|
[ee4f57d] | 429 | volatile uint32_t *tbase; |
---|
| 430 | uint32_t status; |
---|
[01b6ca9] | 431 | |
---|
[509fec9c] | 432 | tbase = (uint32_t*)(sc->base); |
---|
[01b6ca9] | 433 | |
---|
| 434 | /* |
---|
| 435 | * Read status |
---|
| 436 | */ |
---|
| 437 | status = ld_le32(tbase+memCSR5); |
---|
| 438 | st_le32((tbase+memCSR5), status); |
---|
| 439 | |
---|
| 440 | /* |
---|
| 441 | * Frame received? |
---|
| 442 | */ |
---|
| 443 | if( status & 0x000000c0 ) |
---|
| 444 | { |
---|
| 445 | sc->rxInterrupts++; |
---|
| 446 | rtems_event_send(rxDaemonTid, sc->ioevent); |
---|
| 447 | } |
---|
| 448 | } |
---|
[1094cf0d] | 449 | |
---|
| 450 | |
---|
| 451 | |
---|
[01b6ca9] | 452 | static rtems_isr |
---|
| 453 | dec21140Enet_interrupt_handler_entry() |
---|
| 454 | { |
---|
| 455 | int i; |
---|
| 456 | |
---|
| 457 | /* |
---|
| 458 | ** Check all the initialized dec units for interrupt service |
---|
[1094cf0d] | 459 | */ |
---|
[01b6ca9] | 460 | |
---|
| 461 | for(i=0; i< NDECDRIVER; i++ ) |
---|
| 462 | { |
---|
| 463 | if( dec21140_softc[i].base ) |
---|
| 464 | dec21140Enet_interrupt_handler( &dec21140_softc[i] ); |
---|
| 465 | } |
---|
| 466 | } |
---|
| 467 | |
---|
| 468 | |
---|
| 469 | |
---|
| 470 | |
---|
| 471 | |
---|
| 472 | |
---|
| 473 | |
---|
| 474 | |
---|
| 475 | |
---|
| 476 | |
---|
| 477 | /* |
---|
| 478 | * Initialize the ethernet hardware |
---|
| 479 | */ |
---|
| 480 | static void |
---|
| 481 | dec21140Enet_initialize_hardware (struct dec21140_softc *sc) |
---|
| 482 | { |
---|
| 483 | int i,st; |
---|
| 484 | volatile unsigned int *tbase; |
---|
[a3d3d9a] | 485 | volatile unsigned char *cp, *setup_frm, *eaddrs; |
---|
[01b6ca9] | 486 | volatile unsigned char *buffer; |
---|
| 487 | volatile struct MD *rmd; |
---|
| 488 | |
---|
[1094cf0d] | 489 | |
---|
| 490 | #ifdef DEC_DEBUG |
---|
[01b6ca9] | 491 | printk("dec2114x : %02x:%02x:%02x:%02x:%02x:%02x name '%s%d', io %x, mem %x, int %d\n", |
---|
| 492 | sc->arpcom.ac_enaddr[0], sc->arpcom.ac_enaddr[1], |
---|
| 493 | sc->arpcom.ac_enaddr[2], sc->arpcom.ac_enaddr[3], |
---|
| 494 | sc->arpcom.ac_enaddr[4], sc->arpcom.ac_enaddr[5], |
---|
| 495 | sc->arpcom.ac_if.if_name, sc->arpcom.ac_if.if_unit, |
---|
| 496 | sc->port, (unsigned) sc->base, sc->irqInfo.name ); |
---|
[1094cf0d] | 497 | #endif |
---|
[01b6ca9] | 498 | |
---|
| 499 | |
---|
| 500 | |
---|
| 501 | tbase = sc->base; |
---|
| 502 | |
---|
| 503 | /* |
---|
| 504 | * WARNING : First write in CSR6 |
---|
| 505 | * Then Reset the chip ( 1 in CSR0) |
---|
| 506 | */ |
---|
[a3d3d9a] | 507 | st_le32( (tbase+memCSR6), CSR6_INIT); |
---|
| 508 | st_le32( (tbase+memCSR0), RESET_CHIP); |
---|
[01b6ca9] | 509 | rtems_bsp_delay_in_bus_cycles(200); |
---|
| 510 | |
---|
[a3d3d9a] | 511 | st_le32( (tbase+memCSR7), NO_IT); |
---|
[01b6ca9] | 512 | |
---|
| 513 | /* |
---|
| 514 | * Init CSR0 |
---|
| 515 | */ |
---|
[a3d3d9a] | 516 | st_le32( (tbase+memCSR0), CSR0_MODE); |
---|
[01b6ca9] | 517 | |
---|
| 518 | /* |
---|
| 519 | * Init RX ring |
---|
| 520 | */ |
---|
[96e62937] | 521 | cp = (volatile unsigned char *)malloc(((sc->numRxbuffers+sc->numTxbuffers)*sizeof(struct MD)) |
---|
| 522 | + (sc->numTxbuffers*RBUF_SIZE) |
---|
[01b6ca9] | 523 | + CPU_CACHE_ALIGNMENT_FOR_BUFFER); |
---|
| 524 | sc->bufferBase = cp; |
---|
| 525 | cp += (CPU_CACHE_ALIGNMENT_FOR_BUFFER - (int)cp) & (CPU_CACHE_ALIGNMENT_FOR_BUFFER - 1); |
---|
[f7b46db] | 526 | #if defined(__i386__) |
---|
[a3d3d9a] | 527 | #ifdef PCI_BRIDGE_DOES_NOT_ENSURE_CACHE_COHERENCY_FOR_DMA |
---|
[01b6ca9] | 528 | if (_CPU_is_paging_enabled()) |
---|
| 529 | _CPU_change_memory_mapping_attribute |
---|
| 530 | (NULL, cp, |
---|
[96e62937] | 531 | ((sc->numRxbuffers+sc->numTxbuffers)*sizeof(struct MD)) |
---|
| 532 | + (sc->numTxbuffers*RBUF_SIZE), |
---|
[01b6ca9] | 533 | PTE_CACHE_DISABLE | PTE_WRITABLE); |
---|
[8846bbd] | 534 | #endif |
---|
[5a820308] | 535 | #endif |
---|
[01b6ca9] | 536 | rmd = (volatile struct MD*)cp; |
---|
| 537 | sc->MDbase = rmd; |
---|
| 538 | sc->nextRxMD = sc->MDbase; |
---|
[1094cf0d] | 539 | |
---|
[96e62937] | 540 | buffer = cp + ((sc->numRxbuffers+sc->numTxbuffers)*sizeof(struct MD)); |
---|
[01b6ca9] | 541 | st_le32( (tbase+memCSR3), (long)(phys_to_bus((long)(sc->MDbase)))); |
---|
[5a820308] | 542 | |
---|
[96e62937] | 543 | for (i=0 ; i<sc->numRxbuffers; i++) |
---|
[01b6ca9] | 544 | { |
---|
| 545 | struct mbuf *m; |
---|
[a3d3d9a] | 546 | |
---|
[01b6ca9] | 547 | /* allocate an mbuf for each receive descriptor */ |
---|
| 548 | MGETHDR (m, M_WAIT, MT_DATA); |
---|
| 549 | MCLGET (m, M_WAIT); |
---|
| 550 | m->m_pkthdr.rcvif = &sc->arpcom.ac_if; |
---|
| 551 | rmd->m = m; |
---|
[1094cf0d] | 552 | |
---|
[01b6ca9] | 553 | rmd->buf2 = phys_to_bus(rmd+1); |
---|
[a3d3d9a] | 554 | rmd->buf1 = phys_to_bus(mtod(m, void *)); |
---|
[01b6ca9] | 555 | rmd->status = 0x80000000; |
---|
| 556 | rmd->counts = 0xfdc00000 | (RBUF_SIZE); |
---|
| 557 | rmd->next = rmd+1; |
---|
| 558 | rmd++; |
---|
| 559 | } |
---|
| 560 | /* |
---|
| 561 | * mark last RX buffer. |
---|
| 562 | */ |
---|
[96e62937] | 563 | sc->MDbase [sc->numRxbuffers-1].buf2 = 0; |
---|
| 564 | sc->MDbase [sc->numRxbuffers-1].counts = 0xfec00000 | (RBUF_SIZE); |
---|
| 565 | sc->MDbase [sc->numRxbuffers-1].next = sc->MDbase; |
---|
[01b6ca9] | 566 | |
---|
| 567 | |
---|
| 568 | |
---|
| 569 | /* |
---|
| 570 | * Init TX ring |
---|
| 571 | */ |
---|
| 572 | st_le32( (tbase+memCSR4), (long)(phys_to_bus((long)(rmd))) ); |
---|
[96e62937] | 573 | for (i=0 ; i<sc->numTxbuffers; i++){ |
---|
[01b6ca9] | 574 | (rmd+i)->buf2 = phys_to_bus(rmd+i+1); |
---|
| 575 | (rmd+i)->buf1 = phys_to_bus(buffer + (i*RBUF_SIZE)); |
---|
| 576 | (rmd+i)->counts = 0x01000000; |
---|
| 577 | (rmd+i)->status = 0x0; |
---|
| 578 | (rmd+i)->next = rmd+i+1; |
---|
| 579 | (rmd+i)->m = 0; |
---|
[a3d3d9a] | 580 | } |
---|
[01b6ca9] | 581 | |
---|
| 582 | /* |
---|
| 583 | * mark last TX buffer. |
---|
| 584 | */ |
---|
[96e62937] | 585 | (rmd+sc->numTxbuffers-1)->buf2 = phys_to_bus(rmd); |
---|
| 586 | (rmd+sc->numTxbuffers-1)->next = rmd; |
---|
[01b6ca9] | 587 | |
---|
| 588 | |
---|
| 589 | /* |
---|
| 590 | * Build setup frame |
---|
| 591 | */ |
---|
| 592 | setup_frm = (volatile unsigned char *)(bus_to_phys(rmd->buf1)); |
---|
| 593 | eaddrs = (char *)(sc->arpcom.ac_enaddr); |
---|
| 594 | /* Fill the buffer with our physical address. */ |
---|
| 595 | for (i = 1; i < 16; i++) { |
---|
| 596 | *setup_frm++ = eaddrs[0]; |
---|
| 597 | *setup_frm++ = eaddrs[1]; |
---|
| 598 | *setup_frm++ = eaddrs[0]; |
---|
| 599 | *setup_frm++ = eaddrs[1]; |
---|
| 600 | *setup_frm++ = eaddrs[2]; |
---|
| 601 | *setup_frm++ = eaddrs[3]; |
---|
| 602 | *setup_frm++ = eaddrs[2]; |
---|
| 603 | *setup_frm++ = eaddrs[3]; |
---|
| 604 | *setup_frm++ = eaddrs[4]; |
---|
| 605 | *setup_frm++ = eaddrs[5]; |
---|
| 606 | *setup_frm++ = eaddrs[4]; |
---|
| 607 | *setup_frm++ = eaddrs[5]; |
---|
| 608 | } |
---|
| 609 | |
---|
| 610 | /* Add the broadcast address when doing perfect filtering */ |
---|
| 611 | memset((void*) setup_frm, 0xff, 12); |
---|
| 612 | rmd->counts = 0x09000000 | 192 ; |
---|
| 613 | rmd->status = 0x80000000; |
---|
| 614 | st_le32( (tbase+memCSR6), CSR6_INIT | CSR6_TX); |
---|
| 615 | st_le32( (tbase+memCSR1), 1); |
---|
| 616 | |
---|
| 617 | while (rmd->status != 0x7fffffff); |
---|
[a3d3d9a] | 618 | rmd->counts = 0x01000000; |
---|
[01b6ca9] | 619 | |
---|
| 620 | sc->TxMD = rmd+1; |
---|
| 621 | |
---|
| 622 | |
---|
| 623 | |
---|
| 624 | |
---|
| 625 | |
---|
| 626 | sc->irqInfo.hdl = (rtems_irq_hdl)dec21140Enet_interrupt_handler_entry; |
---|
| 627 | sc->irqInfo.on = no_op; |
---|
| 628 | sc->irqInfo.off = no_op; |
---|
| 629 | sc->irqInfo.isOn = dec21140IsOn; |
---|
| 630 | |
---|
| 631 | #ifdef BSP_SHARED_HANDLER_SUPPORT |
---|
| 632 | st = BSP_install_rtems_shared_irq_handler( &sc->irqInfo ); |
---|
| 633 | #else |
---|
| 634 | st = BSP_install_rtems_irq_handler( &sc->irqInfo ); |
---|
| 635 | #endif |
---|
[1094cf0d] | 636 | |
---|
[01b6ca9] | 637 | if (!st) |
---|
| 638 | rtems_panic ("dec2114x : Interrupt name %d already in use\n", sc->irqInfo.name ); |
---|
[1094cf0d] | 639 | } |
---|
| 640 | |
---|
[01b6ca9] | 641 | |
---|
| 642 | |
---|
| 643 | |
---|
| 644 | |
---|
| 645 | |
---|
| 646 | |
---|
[1094cf0d] | 647 | static void |
---|
| 648 | dec21140_rxDaemon (void *arg) |
---|
| 649 | { |
---|
[01b6ca9] | 650 | volatile unsigned int *tbase; |
---|
| 651 | volatile struct MD *rmd; |
---|
| 652 | struct dec21140_softc *sc; |
---|
[96e62937] | 653 | struct ifnet *ifp; |
---|
[01b6ca9] | 654 | struct ether_header *eh; |
---|
| 655 | struct mbuf *m; |
---|
| 656 | unsigned int i,len; |
---|
| 657 | rtems_event_set events; |
---|
| 658 | |
---|
| 659 | for (;;) |
---|
| 660 | { |
---|
| 661 | |
---|
| 662 | rtems_bsdnet_event_receive( RTEMS_ALL_EVENTS, |
---|
| 663 | RTEMS_WAIT|RTEMS_EVENT_ANY, |
---|
| 664 | RTEMS_NO_TIMEOUT, |
---|
| 665 | &events); |
---|
| 666 | |
---|
| 667 | for(i=0; i< NDECDRIVER; i++ ) |
---|
| 668 | { |
---|
| 669 | sc = &dec21140_softc[i]; |
---|
| 670 | if( sc->base ) |
---|
| 671 | { |
---|
| 672 | if( events & sc->ioevent ) |
---|
| 673 | { |
---|
| 674 | ifp = &sc->arpcom.ac_if; |
---|
| 675 | tbase = sc->base; |
---|
| 676 | rmd = sc->nextRxMD; |
---|
| 677 | |
---|
| 678 | /* |
---|
| 679 | ** Read off all the packets we've received on this unit |
---|
| 680 | */ |
---|
| 681 | while((rmd->status & 0x80000000) == 0) |
---|
| 682 | { |
---|
| 683 | /* printk("unit %i rx\n", ifp->if_unit ); */ |
---|
[a3d3d9a] | 684 | |
---|
[01b6ca9] | 685 | /* pass on the packet in the mbuf */ |
---|
| 686 | len = (rmd->status >> 16) & 0x7ff; |
---|
| 687 | m = (struct mbuf *)(rmd->m); |
---|
| 688 | m->m_len = m->m_pkthdr.len = len - sizeof(struct ether_header); |
---|
| 689 | eh = mtod (m, struct ether_header *); |
---|
| 690 | m->m_data += sizeof(struct ether_header); |
---|
| 691 | ether_input (ifp, eh, m); |
---|
| 692 | |
---|
| 693 | /* get a new mbuf for the 21140 */ |
---|
| 694 | MGETHDR (m, M_WAIT, MT_DATA); |
---|
| 695 | MCLGET (m, M_WAIT); |
---|
| 696 | m->m_pkthdr.rcvif = ifp; |
---|
| 697 | rmd->m = m; |
---|
| 698 | rmd->buf1 = phys_to_bus(mtod(m, void *)); |
---|
| 699 | |
---|
| 700 | /* mark the descriptor as ready to receive */ |
---|
| 701 | rmd->status = 0x80000000; |
---|
[a3d3d9a] | 702 | |
---|
[01b6ca9] | 703 | rmd=rmd->next; |
---|
| 704 | } |
---|
[1094cf0d] | 705 | |
---|
[01b6ca9] | 706 | sc->nextRxMD = rmd; |
---|
| 707 | } |
---|
| 708 | } |
---|
| 709 | } |
---|
[1094cf0d] | 710 | |
---|
[01b6ca9] | 711 | } |
---|
[1094cf0d] | 712 | } |
---|
| 713 | |
---|
[01b6ca9] | 714 | |
---|
| 715 | |
---|
| 716 | |
---|
| 717 | |
---|
| 718 | |
---|
| 719 | |
---|
[1094cf0d] | 720 | static void |
---|
| 721 | sendpacket (struct ifnet *ifp, struct mbuf *m) |
---|
| 722 | { |
---|
[01b6ca9] | 723 | struct dec21140_softc *dp = ifp->if_softc; |
---|
| 724 | volatile struct MD *tmd; |
---|
| 725 | volatile unsigned char *temp; |
---|
| 726 | struct mbuf *n; |
---|
| 727 | unsigned int len; |
---|
| 728 | volatile unsigned int *tbase; |
---|
| 729 | |
---|
| 730 | tbase = dp->base; |
---|
| 731 | /* |
---|
| 732 | * Waiting for Transmitter ready |
---|
[a3d3d9a] | 733 | */ |
---|
[01b6ca9] | 734 | |
---|
| 735 | tmd = dp->TxMD; |
---|
| 736 | n = m; |
---|
| 737 | |
---|
| 738 | while ((tmd->status & 0x80000000) != 0) |
---|
| 739 | { |
---|
| 740 | tmd=tmd->next; |
---|
| 741 | } |
---|
| 742 | |
---|
| 743 | len = 0; |
---|
| 744 | temp = (volatile unsigned char *)(bus_to_phys(tmd->buf1)); |
---|
[a3d3d9a] | 745 | |
---|
[01b6ca9] | 746 | for (;;) |
---|
| 747 | { |
---|
| 748 | len += m->m_len; |
---|
| 749 | memcpy((void*) temp, (char *)m->m_data, m->m_len); |
---|
| 750 | temp += m->m_len ; |
---|
| 751 | if ((m = m->m_next) == NULL) |
---|
| 752 | break; |
---|
| 753 | } |
---|
[1094cf0d] | 754 | |
---|
[01b6ca9] | 755 | if (len < ET_MINLEN) len = ET_MINLEN; |
---|
[a3d3d9a] | 756 | tmd->counts = 0xe1000000 | (len & 0x7ff); |
---|
[01b6ca9] | 757 | tmd->status = 0x80000000; |
---|
[5a820308] | 758 | |
---|
[01b6ca9] | 759 | st_le32( (tbase+memCSR1), 0x1); |
---|
[5a820308] | 760 | |
---|
[01b6ca9] | 761 | m_freem(n); |
---|
| 762 | |
---|
| 763 | dp->TxMD = tmd->next; |
---|
[1094cf0d] | 764 | } |
---|
| 765 | |
---|
[01b6ca9] | 766 | |
---|
| 767 | |
---|
| 768 | |
---|
| 769 | |
---|
[1094cf0d] | 770 | /* |
---|
| 771 | * Driver transmit daemon |
---|
| 772 | */ |
---|
| 773 | void |
---|
| 774 | dec21140_txDaemon (void *arg) |
---|
| 775 | { |
---|
[01b6ca9] | 776 | struct dec21140_softc *sc; |
---|
| 777 | struct ifnet *ifp; |
---|
| 778 | struct mbuf *m; |
---|
| 779 | int i; |
---|
| 780 | rtems_event_set events; |
---|
| 781 | |
---|
[a3d3d9a] | 782 | for (;;) |
---|
[01b6ca9] | 783 | { |
---|
[1094cf0d] | 784 | /* |
---|
[01b6ca9] | 785 | * Wait for packets bound for any of the dec units |
---|
[1094cf0d] | 786 | */ |
---|
[01b6ca9] | 787 | rtems_bsdnet_event_receive( RTEMS_ALL_EVENTS, |
---|
[a3d3d9a] | 788 | RTEMS_EVENT_ANY | RTEMS_WAIT, |
---|
[01b6ca9] | 789 | RTEMS_NO_TIMEOUT, &events); |
---|
| 790 | |
---|
| 791 | for(i=0; i< NDECDRIVER; i++ ) |
---|
| 792 | { |
---|
| 793 | sc = &dec21140_softc[i]; |
---|
| 794 | if( sc->base ) |
---|
| 795 | { |
---|
| 796 | if( events & sc->ioevent ) |
---|
| 797 | { |
---|
| 798 | ifp = &sc->arpcom.ac_if; |
---|
| 799 | |
---|
| 800 | /* |
---|
| 801 | * Send packets till queue is empty |
---|
| 802 | */ |
---|
[a3d3d9a] | 803 | for(;;) |
---|
[01b6ca9] | 804 | { |
---|
| 805 | IF_DEQUEUE(&ifp->if_snd, m); |
---|
| 806 | if( !m ) break; |
---|
| 807 | /* printk("unit %i tx\n", ifp->if_unit ); */ |
---|
| 808 | sendpacket (ifp, m); |
---|
| 809 | } |
---|
| 810 | |
---|
| 811 | ifp->if_flags &= ~IFF_OACTIVE; |
---|
| 812 | } |
---|
| 813 | } |
---|
| 814 | } |
---|
| 815 | |
---|
| 816 | } |
---|
| 817 | } |
---|
| 818 | |
---|
| 819 | |
---|
[1094cf0d] | 820 | |
---|
| 821 | |
---|
| 822 | static void |
---|
| 823 | dec21140_start (struct ifnet *ifp) |
---|
| 824 | { |
---|
[01b6ca9] | 825 | struct dec21140_softc *sc = ifp->if_softc; |
---|
| 826 | rtems_event_send( txDaemonTid, sc->ioevent ); |
---|
| 827 | ifp->if_flags |= IFF_OACTIVE; |
---|
[1094cf0d] | 828 | } |
---|
| 829 | |
---|
[01b6ca9] | 830 | |
---|
| 831 | |
---|
| 832 | |
---|
| 833 | |
---|
[1094cf0d] | 834 | /* |
---|
| 835 | * Initialize and start the device |
---|
| 836 | */ |
---|
| 837 | static void |
---|
| 838 | dec21140_init (void *arg) |
---|
| 839 | { |
---|
[01b6ca9] | 840 | struct dec21140_softc *sc = arg; |
---|
| 841 | struct ifnet *ifp = &sc->arpcom.ac_if; |
---|
| 842 | volatile unsigned int *tbase; |
---|
| 843 | |
---|
| 844 | /* |
---|
| 845 | * Set up DEC21140 hardware if its not already been done |
---|
| 846 | */ |
---|
| 847 | if( !sc->irqInfo.hdl ) |
---|
| 848 | { |
---|
| 849 | dec21140Enet_initialize_hardware (sc); |
---|
| 850 | } |
---|
| 851 | |
---|
| 852 | /* |
---|
| 853 | * Enable RX and TX |
---|
| 854 | */ |
---|
| 855 | tbase = sc->base; |
---|
| 856 | st_le32( (tbase+memCSR5), IT_SETUP); |
---|
[a3d3d9a] | 857 | st_le32( (tbase+memCSR7), IT_SETUP); |
---|
[01b6ca9] | 858 | st_le32( (unsigned int*)(tbase+memCSR6), CSR6_INIT | CSR6_TXRX); |
---|
| 859 | |
---|
| 860 | /* |
---|
| 861 | * Tell the world that we're running. |
---|
| 862 | */ |
---|
| 863 | ifp->if_flags |= IFF_RUNNING; |
---|
| 864 | } |
---|
| 865 | |
---|
| 866 | |
---|
| 867 | |
---|
[1094cf0d] | 868 | |
---|
| 869 | |
---|
| 870 | |
---|
| 871 | |
---|
| 872 | /* |
---|
| 873 | * Stop the device |
---|
| 874 | */ |
---|
| 875 | static void |
---|
| 876 | dec21140_stop (struct dec21140_softc *sc) |
---|
| 877 | { |
---|
[5a820308] | 878 | volatile unsigned int *tbase; |
---|
[1094cf0d] | 879 | struct ifnet *ifp = &sc->arpcom.ac_if; |
---|
| 880 | |
---|
| 881 | ifp->if_flags &= ~IFF_RUNNING; |
---|
| 882 | |
---|
| 883 | /* |
---|
| 884 | * Stop the transmitter |
---|
| 885 | */ |
---|
[01b6ca9] | 886 | tbase = sc->base; |
---|
[5a820308] | 887 | st_le32( (tbase+memCSR7), NO_IT); |
---|
| 888 | st_le32( (tbase+memCSR6), CSR6_INIT); |
---|
[01b6ca9] | 889 | |
---|
| 890 | /* free((void*)sc->bufferBase); */ |
---|
[1094cf0d] | 891 | } |
---|
| 892 | |
---|
| 893 | |
---|
| 894 | /* |
---|
| 895 | * Show interface statistics |
---|
| 896 | */ |
---|
| 897 | static void |
---|
| 898 | dec21140_stats (struct dec21140_softc *sc) |
---|
| 899 | { |
---|
| 900 | printf (" Rx Interrupts:%-8lu", sc->rxInterrupts); |
---|
| 901 | printf (" Not First:%-8lu", sc->rxNotFirst); |
---|
| 902 | printf (" Not Last:%-8lu\n", sc->rxNotLast); |
---|
| 903 | printf (" Giant:%-8lu", sc->rxGiant); |
---|
| 904 | printf (" Runt:%-8lu", sc->rxRunt); |
---|
| 905 | printf (" Non-octet:%-8lu\n", sc->rxNonOctet); |
---|
| 906 | printf (" Bad CRC:%-8lu", sc->rxBadCRC); |
---|
| 907 | printf (" Overrun:%-8lu", sc->rxOverrun); |
---|
| 908 | printf (" Collision:%-8lu\n", sc->rxCollision); |
---|
| 909 | |
---|
| 910 | printf (" Tx Interrupts:%-8lu", sc->txInterrupts); |
---|
| 911 | printf (" Deferred:%-8lu", sc->txDeferred); |
---|
| 912 | printf (" Missed Hearbeat:%-8lu\n", sc->txHeartbeat); |
---|
| 913 | printf (" No Carrier:%-8lu", sc->txLostCarrier); |
---|
| 914 | printf ("Retransmit Limit:%-8lu", sc->txRetryLimit); |
---|
| 915 | printf (" Late Collision:%-8lu\n", sc->txLateCollision); |
---|
| 916 | printf (" Underrun:%-8lu", sc->txUnderrun); |
---|
| 917 | printf (" Raw output wait:%-8lu\n", sc->txRawWait); |
---|
| 918 | } |
---|
| 919 | |
---|
[01b6ca9] | 920 | |
---|
| 921 | |
---|
| 922 | |
---|
[1094cf0d] | 923 | /* |
---|
| 924 | * Driver ioctl handler |
---|
| 925 | */ |
---|
| 926 | static int |
---|
| 927 | dec21140_ioctl (struct ifnet *ifp, int command, caddr_t data) |
---|
| 928 | { |
---|
[01b6ca9] | 929 | struct dec21140_softc *sc = ifp->if_softc; |
---|
| 930 | int error = 0; |
---|
| 931 | |
---|
| 932 | switch (command) { |
---|
| 933 | case SIOCGIFADDR: |
---|
| 934 | case SIOCSIFADDR: |
---|
| 935 | ether_ioctl (ifp, command, data); |
---|
| 936 | break; |
---|
| 937 | |
---|
| 938 | case SIOCSIFFLAGS: |
---|
| 939 | switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) { |
---|
| 940 | case IFF_RUNNING: |
---|
| 941 | dec21140_stop (sc); |
---|
| 942 | break; |
---|
| 943 | |
---|
| 944 | case IFF_UP: |
---|
| 945 | dec21140_init (sc); |
---|
| 946 | break; |
---|
| 947 | |
---|
| 948 | case IFF_UP | IFF_RUNNING: |
---|
| 949 | dec21140_stop (sc); |
---|
| 950 | dec21140_init (sc); |
---|
| 951 | break; |
---|
| 952 | |
---|
| 953 | default: |
---|
| 954 | break; |
---|
| 955 | } |
---|
| 956 | break; |
---|
| 957 | |
---|
| 958 | case SIO_RTEMS_SHOW_STATS: |
---|
| 959 | dec21140_stats (sc); |
---|
| 960 | break; |
---|
[a3d3d9a] | 961 | |
---|
[01b6ca9] | 962 | /* |
---|
| 963 | * FIXME: All sorts of multicast commands need to be added here! |
---|
| 964 | */ |
---|
| 965 | default: |
---|
| 966 | error = EINVAL; |
---|
| 967 | break; |
---|
| 968 | } |
---|
| 969 | |
---|
| 970 | return error; |
---|
| 971 | } |
---|
| 972 | |
---|
| 973 | |
---|
| 974 | |
---|
| 975 | |
---|
| 976 | |
---|
| 977 | |
---|
| 978 | |
---|
| 979 | /* |
---|
| 980 | int iftap(struct ifnet *ifp, struct ether_header *eh, struct mbuf *m ) |
---|
| 981 | { |
---|
| 982 | int i; |
---|
| 983 | |
---|
| 984 | if( ifp->if_unit == 1 ) return 0; |
---|
| 985 | |
---|
| 986 | printf("unit %i, src ", ifp->if_unit ); |
---|
| 987 | for(i=0; i< ETHER_ADDR_LEN; i++) printf("%02x", (char) eh->ether_shost[i] ); |
---|
| 988 | printf(" dest "); |
---|
| 989 | for(i=0; i< ETHER_ADDR_LEN; i++) printf("%02x", (char) eh->ether_dhost[i] ); |
---|
| 990 | printf("\n"); |
---|
| 991 | |
---|
| 992 | return -1; |
---|
[1094cf0d] | 993 | } |
---|
[01b6ca9] | 994 | */ |
---|
| 995 | |
---|
| 996 | |
---|
| 997 | |
---|
| 998 | |
---|
[1094cf0d] | 999 | |
---|
| 1000 | /* |
---|
| 1001 | * Attach an DEC21140 driver to the system |
---|
| 1002 | */ |
---|
| 1003 | int |
---|
[461fa1bc] | 1004 | rtems_dec21140_driver_attach (struct rtems_bsdnet_ifconfig *config, int attach) |
---|
[1094cf0d] | 1005 | { |
---|
[01b6ca9] | 1006 | struct dec21140_softc *sc; |
---|
| 1007 | struct ifnet *ifp; |
---|
| 1008 | char *unitName; |
---|
| 1009 | int unitNumber; |
---|
| 1010 | int mtu; |
---|
| 1011 | unsigned char cvalue; |
---|
[c22aeb4] | 1012 | #if defined(__i386__) |
---|
[01b6ca9] | 1013 | int signature; |
---|
| 1014 | int value; |
---|
| 1015 | char interrupt; |
---|
| 1016 | int diag; |
---|
| 1017 | unsigned int deviceId; |
---|
[c22aeb4] | 1018 | #endif |
---|
[51b9899] | 1019 | #if defined(__PPC__) |
---|
[01b6ca9] | 1020 | int pbus, pdev, pfun; |
---|
| 1021 | int tmp; |
---|
| 1022 | unsigned int lvalue; |
---|
| 1023 | #endif |
---|
| 1024 | |
---|
| 1025 | |
---|
| 1026 | /* |
---|
| 1027 | * Get the instance number for the board we're going to configure |
---|
| 1028 | * from the user. |
---|
| 1029 | */ |
---|
| 1030 | if( (unitNumber = rtems_bsdnet_parse_driver_name( config, &unitName)) == -1 ) |
---|
| 1031 | { |
---|
| 1032 | return 0; |
---|
| 1033 | } |
---|
| 1034 | if( strcmp(unitName, DRIVER_PREFIX) ) |
---|
| 1035 | { |
---|
| 1036 | printk("dec2114x : unit name '%s' not %s\n", unitName, DRIVER_PREFIX ); |
---|
| 1037 | return 0; |
---|
| 1038 | } |
---|
| 1039 | |
---|
| 1040 | |
---|
[f7b46db] | 1041 | #if defined(__i386__) |
---|
[01b6ca9] | 1042 | /* |
---|
| 1043 | * First, find a DEC board |
---|
| 1044 | */ |
---|
[5a820308] | 1045 | |
---|
[01b6ca9] | 1046 | if (pcib_init() == PCIB_ERR_NOTPRESENT) |
---|
| 1047 | rtems_panic("PCI BIOS not found !!"); |
---|
[a3d3d9a] | 1048 | |
---|
[01b6ca9] | 1049 | /* |
---|
| 1050 | * Try to find the network card on the PCI bus. Probe for a DEC 21140 |
---|
| 1051 | * card first. If not found probe the bus for a DEC/Intel 21143 card. |
---|
| 1052 | */ |
---|
| 1053 | deviceId = PCI_DEVICE_ID_DEC_21140; |
---|
| 1054 | diag = pcib_find_by_devid( PCI_VENDOR_ID_DEC, deviceId, unitNumber-1, &signature); |
---|
| 1055 | |
---|
| 1056 | if ( diag == PCIB_ERR_SUCCESS) |
---|
[df49c60] | 1057 | printk( "DEC 21140 PCI network card found\n" ); |
---|
[01b6ca9] | 1058 | else |
---|
| 1059 | { |
---|
[df49c60] | 1060 | deviceId = PCI_DEVICE_ID_DEC_21143; |
---|
[01b6ca9] | 1061 | diag = pcib_find_by_devid( PCI_VENDOR_ID_DEC, deviceId, unitNumber-1, &signature); |
---|
[df49c60] | 1062 | if ( diag == PCIB_ERR_SUCCESS) |
---|
[01b6ca9] | 1063 | printk( "DEC/Intel 21143 PCI network card found\n" ); |
---|
[df49c60] | 1064 | else |
---|
[1402d56a] | 1065 | { |
---|
| 1066 | printk("No DEC/Intel 21140/3 PCI network card found !!\n"); |
---|
| 1067 | return 0; |
---|
| 1068 | } |
---|
[01b6ca9] | 1069 | } |
---|
[a3d3d9a] | 1070 | #endif |
---|
[51b9899] | 1071 | #if defined(__PPC__) |
---|
[01b6ca9] | 1072 | /* |
---|
| 1073 | * Find the board |
---|
| 1074 | */ |
---|
| 1075 | if( BSP_pciFindDevice( PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21140, |
---|
| 1076 | unitNumber-1, &pbus, &pdev, &pfun) == -1 ) |
---|
| 1077 | { |
---|
| 1078 | if( BSP_pciFindDevice( PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21143, |
---|
| 1079 | unitNumber-1, &pbus, &pdev, &pfun) != -1 ) |
---|
| 1080 | { |
---|
[a3d3d9a] | 1081 | printk("dec21143 : found device '%s', PPC support has not been tested. Using it anyway.\n", |
---|
[01b6ca9] | 1082 | config->name ); |
---|
| 1083 | |
---|
| 1084 | pci_write_config_dword(pbus, |
---|
| 1085 | pdev, |
---|
| 1086 | pfun, |
---|
| 1087 | 0x40, |
---|
| 1088 | PCI_DEVICE_ID_DEC_21143 ); |
---|
| 1089 | |
---|
| 1090 | } |
---|
| 1091 | else |
---|
| 1092 | { |
---|
| 1093 | printk("dec2114x : device '%s' not found on PCI bus\n", config->name ); |
---|
| 1094 | return 0; |
---|
| 1095 | } |
---|
| 1096 | } |
---|
| 1097 | |
---|
| 1098 | #ifdef DEC_DEBUG |
---|
[a3d3d9a] | 1099 | else |
---|
[01b6ca9] | 1100 | { |
---|
[a3d3d9a] | 1101 | printk("dec21140 : found device '%s', bus 0x%02x, dev 0x%02x, func 0x%02x\n", |
---|
[01b6ca9] | 1102 | config->name, pbus, pdev, pfun); |
---|
| 1103 | } |
---|
| 1104 | #endif |
---|
| 1105 | |
---|
| 1106 | #endif |
---|
| 1107 | |
---|
| 1108 | |
---|
| 1109 | |
---|
| 1110 | |
---|
| 1111 | if ((unitNumber < 1) || (unitNumber > NDECDRIVER)) |
---|
| 1112 | { |
---|
| 1113 | printk("dec2114x : unit %i is invalid, must be (1 <= n <= %d)\n", unitNumber); |
---|
| 1114 | return 0; |
---|
| 1115 | } |
---|
| 1116 | |
---|
| 1117 | sc = &dec21140_softc[unitNumber - 1]; |
---|
| 1118 | ifp = &sc->arpcom.ac_if; |
---|
[a3d3d9a] | 1119 | if (ifp->if_softc != NULL) |
---|
[01b6ca9] | 1120 | { |
---|
| 1121 | printk("dec2114x : unit %i already in use.\n", unitNumber ); |
---|
| 1122 | return 0; |
---|
| 1123 | } |
---|
| 1124 | |
---|
| 1125 | |
---|
| 1126 | /* |
---|
| 1127 | ** Get this unit's rx/tx event |
---|
| 1128 | */ |
---|
| 1129 | sc->ioevent = unit_signals[unitNumber-1]; |
---|
| 1130 | |
---|
[96e62937] | 1131 | /* |
---|
[a3d3d9a] | 1132 | ** Save the buffer counts |
---|
[96e62937] | 1133 | */ |
---|
| 1134 | sc->numRxbuffers = (config->rbuf_count) ? config->rbuf_count : NRXBUFS; |
---|
| 1135 | sc->numTxbuffers = (config->xbuf_count) ? config->xbuf_count : NTXBUFS; |
---|
| 1136 | |
---|
[01b6ca9] | 1137 | |
---|
| 1138 | /* |
---|
| 1139 | * Get card address spaces & retrieve its isr vector |
---|
| 1140 | */ |
---|
[f7b46db] | 1141 | #if defined(__i386__) |
---|
[df49c60] | 1142 | |
---|
[01b6ca9] | 1143 | /* the 21143 chip must be enabled before it can be accessed */ |
---|
| 1144 | if ( deviceId == PCI_DEVICE_ID_DEC_21143 ) |
---|
[df49c60] | 1145 | pcib_conf_write32( signature, 0x40, 0 ); |
---|
| 1146 | |
---|
[01b6ca9] | 1147 | pcib_conf_read32(signature, 16, &value); |
---|
| 1148 | sc->port = value & ~IO_MASK; |
---|
[a3d3d9a] | 1149 | |
---|
[01b6ca9] | 1150 | pcib_conf_read32(signature, 20, &value); |
---|
| 1151 | if (_CPU_is_paging_enabled()) |
---|
| 1152 | _CPU_map_phys_address((void **) &(sc->base), |
---|
| 1153 | (void *)(value & ~MEM_MASK), |
---|
| 1154 | DEC_REGISTER_SIZE , |
---|
| 1155 | PTE_CACHE_DISABLE | PTE_WRITABLE); |
---|
| 1156 | else |
---|
| 1157 | sc->base = (unsigned int *)(value & ~MEM_MASK); |
---|
[a3d3d9a] | 1158 | |
---|
[01b6ca9] | 1159 | pcib_conf_read8(signature, 60, &interrupt); |
---|
| 1160 | cvalue = interrupt; |
---|
[5a820308] | 1161 | #endif |
---|
[51b9899] | 1162 | #if defined(__PPC__) |
---|
[01b6ca9] | 1163 | (void)pci_read_config_dword(pbus, |
---|
| 1164 | pdev, |
---|
| 1165 | pfun, |
---|
| 1166 | PCI_BASE_ADDRESS_0, |
---|
| 1167 | &lvalue); |
---|
[5a820308] | 1168 | |
---|
[01b6ca9] | 1169 | sc->port = lvalue & (unsigned int)(~IO_MASK); |
---|
[a3d3d9a] | 1170 | |
---|
[01b6ca9] | 1171 | (void)pci_read_config_dword(pbus, |
---|
| 1172 | pdev, |
---|
| 1173 | pfun, |
---|
| 1174 | PCI_BASE_ADDRESS_1, |
---|
| 1175 | &lvalue); |
---|
| 1176 | |
---|
[a3d3d9a] | 1177 | tmp = (unsigned int)(lvalue & (unsigned int)(~MEM_MASK)) |
---|
[01b6ca9] | 1178 | + (unsigned int)PCI_MEM_BASE; |
---|
| 1179 | |
---|
| 1180 | sc->base = (unsigned int *)(tmp); |
---|
| 1181 | |
---|
| 1182 | pci_read_config_byte(pbus, |
---|
| 1183 | pdev, |
---|
| 1184 | pfun, |
---|
| 1185 | PCI_INTERRUPT_LINE, |
---|
| 1186 | &cvalue); |
---|
| 1187 | |
---|
[5a820308] | 1188 | #endif |
---|
[01b6ca9] | 1189 | |
---|
| 1190 | /* |
---|
| 1191 | ** Prep the board |
---|
| 1192 | */ |
---|
[96e62937] | 1193 | |
---|
[51b9899] | 1194 | #if defined(__PPC__) |
---|
[01b6ca9] | 1195 | pci_write_config_word(pbus, pdev, pfun, |
---|
[96e62937] | 1196 | #endif |
---|
| 1197 | #if defined(__i386__) |
---|
[cd38196f] | 1198 | pcib_conf_write16(signature, |
---|
[96e62937] | 1199 | #endif |
---|
[cd38196f] | 1200 | PCI_COMMAND, |
---|
| 1201 | (uint16_t) ( PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER ) ); |
---|
[01b6ca9] | 1202 | |
---|
| 1203 | /* |
---|
| 1204 | ** Store the interrupt name, we'll use it later when we initialize |
---|
| 1205 | ** the board. |
---|
| 1206 | */ |
---|
| 1207 | memset(&sc->irqInfo,0,sizeof(rtems_irq_connect_data)); |
---|
| 1208 | sc->irqInfo.name = cvalue; |
---|
| 1209 | |
---|
| 1210 | |
---|
| 1211 | /* printk("dec2114x : unit %d base address %08x.\n", unitNumber, sc->base ); */ |
---|
| 1212 | |
---|
| 1213 | |
---|
| 1214 | /* |
---|
| 1215 | ** Setup ethernet address |
---|
| 1216 | */ |
---|
| 1217 | if (config->hardware_address) { |
---|
| 1218 | memcpy (sc->arpcom.ac_enaddr, config->hardware_address, |
---|
| 1219 | ETHER_ADDR_LEN); |
---|
| 1220 | } |
---|
| 1221 | else { |
---|
| 1222 | union {char c[64]; unsigned short s[32];} rombuf; |
---|
| 1223 | int i; |
---|
| 1224 | |
---|
| 1225 | for (i=0; i<32; i++){ |
---|
| 1226 | rombuf.s[i] = eeget16( sc->base + memCSR9, i); |
---|
| 1227 | } |
---|
[f7b46db] | 1228 | #if defined(__i386__) |
---|
[01b6ca9] | 1229 | for (i=0 ; i<(ETHER_ADDR_LEN/2); i++){ |
---|
| 1230 | sc->arpcom.ac_enaddr[2*i] = rombuf.c[20+2*i+1]; |
---|
| 1231 | sc->arpcom.ac_enaddr[2*i+1] = rombuf.c[20+2*i]; |
---|
[a3d3d9a] | 1232 | } |
---|
[38b81b5] | 1233 | #endif |
---|
[51b9899] | 1234 | #if defined(__PPC__) |
---|
[01b6ca9] | 1235 | memcpy (sc->arpcom.ac_enaddr, rombuf.c+20, ETHER_ADDR_LEN); |
---|
| 1236 | #endif |
---|
| 1237 | } |
---|
| 1238 | |
---|
| 1239 | if (config->mtu) |
---|
| 1240 | mtu = config->mtu; |
---|
| 1241 | else |
---|
| 1242 | mtu = ETHERMTU; |
---|
| 1243 | |
---|
| 1244 | sc->acceptBroadcast = !config->ignore_broadcast; |
---|
| 1245 | |
---|
| 1246 | /* |
---|
| 1247 | * Set up network interface values |
---|
| 1248 | */ |
---|
| 1249 | |
---|
| 1250 | /* ifp->if_tap = iftap; */ |
---|
| 1251 | |
---|
| 1252 | ifp->if_softc = sc; |
---|
| 1253 | ifp->if_unit = unitNumber; |
---|
| 1254 | ifp->if_name = unitName; |
---|
| 1255 | ifp->if_mtu = mtu; |
---|
| 1256 | ifp->if_init = dec21140_init; |
---|
| 1257 | ifp->if_ioctl = dec21140_ioctl; |
---|
| 1258 | ifp->if_start = dec21140_start; |
---|
| 1259 | ifp->if_output = ether_output; |
---|
| 1260 | ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX; |
---|
| 1261 | if (ifp->if_snd.ifq_maxlen == 0) |
---|
| 1262 | ifp->if_snd.ifq_maxlen = ifqmaxlen; |
---|
| 1263 | |
---|
| 1264 | /* |
---|
| 1265 | * Attach the interface |
---|
| 1266 | */ |
---|
| 1267 | if_attach (ifp); |
---|
| 1268 | ether_ifattach (ifp); |
---|
| 1269 | |
---|
| 1270 | #ifdef DEC_DEBUG |
---|
| 1271 | printk( "dec2114x : driver attached\n" ); |
---|
[38b81b5] | 1272 | #endif |
---|
[01b6ca9] | 1273 | |
---|
| 1274 | |
---|
| 1275 | /* |
---|
| 1276 | * Start driver tasks if this is the first dec unit initialized |
---|
| 1277 | */ |
---|
[a3d3d9a] | 1278 | if (txDaemonTid == 0) |
---|
[01b6ca9] | 1279 | { |
---|
| 1280 | rxDaemonTid = rtems_bsdnet_newproc( "DCrx", 4096, |
---|
| 1281 | dec21140_rxDaemon, NULL); |
---|
[a3d3d9a] | 1282 | |
---|
[01b6ca9] | 1283 | txDaemonTid = rtems_bsdnet_newproc( "DCtx", 4096, |
---|
| 1284 | dec21140_txDaemon, NULL); |
---|
| 1285 | #ifdef DEC_DEBUG |
---|
| 1286 | printk( "dec2114x : driver tasks created\n" ); |
---|
| 1287 | #endif |
---|
| 1288 | } |
---|
| 1289 | |
---|
| 1290 | return 1; |
---|
[1094cf0d] | 1291 | }; |
---|
[01b6ca9] | 1292 | |
---|
[a1efd7a] | 1293 | #endif /* DEC21140_SUPPORTED */ |
---|