[1f14ff4] | 1 | /* |
---|
| 2 | ------------------------------------------------------------------------ |
---|
[00bf7745] | 3 | |
---|
[1f14ff4] | 4 | Copyright Cybertec Pty Ltd, 2000 |
---|
| 5 | All rights reserved Cybertec Pty Ltd, 2000 |
---|
[00bf7745] | 6 | |
---|
| 7 | Port to the DIMM PC copyright (c) 2004 Angelo Fraietta |
---|
| 8 | This project has been assisted by the Commonwealth Government |
---|
| 9 | through the Australia Council, its arts funding and advisory body. |
---|
| 10 | |
---|
[1f14ff4] | 11 | COPYRIGHT (c) 1989-1998. |
---|
| 12 | On-Line Applications Research Corporation (OAR). |
---|
| 13 | |
---|
| 14 | The license and distribution terms for this file may be |
---|
| 15 | found in the file LICENSE in this distribution or at |
---|
[c499856] | 16 | http://www.rtems.org/license/LICENSE. |
---|
[a2117cd6] | 17 | |
---|
[1f14ff4] | 18 | ------------------------------------------------------------------------ |
---|
| 19 | |
---|
[00bf7745] | 20 | CS8900 RTEMS driver. |
---|
[1f14ff4] | 21 | |
---|
[00bf7745] | 22 | See the header file for details. |
---|
[a3d3d9a] | 23 | |
---|
[a2117cd6] | 24 | */ |
---|
| 25 | |
---|
[d8d6a08] | 26 | #define __INSIDE_RTEMS_BSD_TCPIP_STACK__ |
---|
| 27 | |
---|
[c8e8f119] | 28 | #include <errno.h> |
---|
[a2117cd6] | 29 | #include <string.h> |
---|
| 30 | #include <stdio.h> |
---|
| 31 | |
---|
[230acc55] | 32 | #include <libchip/cs8900.h> |
---|
[a2117cd6] | 33 | |
---|
[1f14ff4] | 34 | /* |
---|
[a2117cd6] | 35 | * We expect to be able to read a complete packet into an mbuf. |
---|
[1f14ff4] | 36 | */ |
---|
| 37 | |
---|
[a2117cd6] | 38 | #if (MCLBYTES < 1520) |
---|
| 39 | #error "CS8900 Driver must have MCLBYTES >= 1520" |
---|
| 40 | #endif |
---|
| 41 | |
---|
| 42 | /* |
---|
| 43 | * Task event usage. |
---|
| 44 | */ |
---|
| 45 | |
---|
| 46 | #define CS8900_RX_OK_EVENT RTEMS_EVENT_1 |
---|
| 47 | #define CS8900_TX_START_EVENT RTEMS_EVENT_1 |
---|
| 48 | #define CS8900_TX_OK_EVENT RTEMS_EVENT_2 |
---|
| 49 | #define CS8900_TX_WAIT_EVENT RTEMS_EVENT_3 |
---|
| 50 | |
---|
| 51 | /* |
---|
| 52 | * IO Packet Page inteface. |
---|
| 53 | */ |
---|
| 54 | |
---|
| 55 | static inline unsigned short |
---|
[00bf7745] | 56 | io_pp_get_reg_16 (cs8900_device *cs, unsigned short reg) |
---|
[1f14ff4] | 57 | { |
---|
[00bf7745] | 58 | rtems_interrupt_level level; |
---|
| 59 | unsigned short data; |
---|
| 60 | rtems_interrupt_disable (level); |
---|
| 61 | cs8900_io_set_reg (cs, CS8900_IO_PACKET_PAGE_PTR, |
---|
[a2117cd6] | 62 | 0x3000 | CS8900_PPP_AUTO_INCREMENT | reg); |
---|
[00bf7745] | 63 | data = cs8900_io_get_reg (cs, CS8900_IO_PP_DATA_PORT0); |
---|
| 64 | rtems_interrupt_enable (level); |
---|
| 65 | return data; |
---|
[a2117cd6] | 66 | } |
---|
[1f14ff4] | 67 | |
---|
[8593651] | 68 | static inline uint32_t |
---|
| 69 | io_pp_get_reg_32 (cs8900_device *cs, uint16_t reg) |
---|
[1f14ff4] | 70 | { |
---|
[00bf7745] | 71 | rtems_interrupt_level level; |
---|
[8593651] | 72 | uint32_t data; |
---|
[00bf7745] | 73 | rtems_interrupt_disable (level); |
---|
| 74 | cs8900_io_set_reg (cs, CS8900_IO_PACKET_PAGE_PTR, |
---|
[a2117cd6] | 75 | 0x3000 | CS8900_PPP_AUTO_INCREMENT | reg); |
---|
[8593651] | 76 | data = cs8900_io_get_reg (cs, CS8900_IO_PP_DATA_PORT0); |
---|
| 77 | data <<= 16; |
---|
| 78 | data |= cs8900_io_get_reg (cs, CS8900_IO_PP_DATA_PORT1); |
---|
[00bf7745] | 79 | rtems_interrupt_enable (level); |
---|
| 80 | return data; |
---|
[a2117cd6] | 81 | } |
---|
[1f14ff4] | 82 | |
---|
[a2117cd6] | 83 | static inline void |
---|
[00bf7745] | 84 | io_pp_set_reg_16 (cs8900_device *cs, unsigned short reg, unsigned short data) |
---|
[1f14ff4] | 85 | { |
---|
[00bf7745] | 86 | rtems_interrupt_level level; |
---|
| 87 | rtems_interrupt_disable (level); |
---|
| 88 | cs8900_io_set_reg (cs, CS8900_IO_PACKET_PAGE_PTR, |
---|
[a2117cd6] | 89 | 0x3000 | CS8900_PPP_AUTO_INCREMENT | reg); |
---|
[00bf7745] | 90 | cs8900_io_set_reg (cs, CS8900_IO_PP_DATA_PORT0, data); |
---|
| 91 | rtems_interrupt_enable (level); |
---|
[a2117cd6] | 92 | } |
---|
[1f14ff4] | 93 | |
---|
[a2117cd6] | 94 | static inline void |
---|
[00bf7745] | 95 | io_pp_set_reg_32 (cs8900_device *cs, unsigned short reg, unsigned long data) |
---|
[1f14ff4] | 96 | { |
---|
[00bf7745] | 97 | cs8900_io_set_reg (cs, CS8900_IO_PACKET_PAGE_PTR, |
---|
[a2117cd6] | 98 | 0x3000 | CS8900_PPP_AUTO_INCREMENT | reg); |
---|
[00bf7745] | 99 | cs8900_io_set_reg (cs, CS8900_IO_PP_DATA_PORT0, data >> 16); |
---|
| 100 | cs8900_io_set_reg (cs, CS8900_IO_PP_DATA_PORT1, data); |
---|
[a2117cd6] | 101 | } |
---|
[1f14ff4] | 102 | |
---|
[a2117cd6] | 103 | static inline void |
---|
[00bf7745] | 104 | io_pp_bit_set_reg_16 (cs8900_device *cs, unsigned short reg, unsigned short mask) |
---|
[1f14ff4] | 105 | { |
---|
[00bf7745] | 106 | rtems_interrupt_level level; |
---|
| 107 | rtems_interrupt_disable (level); |
---|
| 108 | io_pp_set_reg_16 (cs, reg, io_pp_get_reg_16 (cs, reg) | mask); |
---|
| 109 | rtems_interrupt_enable (level); |
---|
[a2117cd6] | 110 | } |
---|
[1f14ff4] | 111 | |
---|
[a2117cd6] | 112 | static inline void |
---|
[00bf7745] | 113 | io_pp_bit_clear_reg_16 (cs8900_device *cs, unsigned short reg, unsigned short mask) |
---|
[1f14ff4] | 114 | { |
---|
[00bf7745] | 115 | rtems_interrupt_level level; |
---|
| 116 | rtems_interrupt_disable (level); |
---|
| 117 | io_pp_set_reg_16 (cs, reg, io_pp_get_reg_16 (cs, reg) & ~mask); |
---|
| 118 | rtems_interrupt_enable (level); |
---|
[a2117cd6] | 119 | } |
---|
[1f14ff4] | 120 | |
---|
[a2117cd6] | 121 | /* |
---|
| 122 | * Memory Mapped Packet Page interface. |
---|
[00bf7745] | 123 | * |
---|
| 124 | * If the BSP does not configure mem_base use the I/O register accesses. |
---|
[a2117cd6] | 125 | */ |
---|
| 126 | |
---|
| 127 | static inline unsigned short |
---|
[00bf7745] | 128 | mem_pp_get_reg (cs8900_device *cs, unsigned short reg) |
---|
[a2117cd6] | 129 | { |
---|
[00bf7745] | 130 | if (!cs->mem_base) |
---|
| 131 | return io_pp_get_reg_16 (cs, reg); |
---|
| 132 | return cs8900_mem_get_reg (cs, reg); |
---|
[1f14ff4] | 133 | } |
---|
| 134 | |
---|
[a2117cd6] | 135 | static inline void |
---|
[00bf7745] | 136 | mem_pp_set_reg (cs8900_device *cs, unsigned short reg, unsigned short data) |
---|
[1f14ff4] | 137 | { |
---|
[00bf7745] | 138 | if (!cs->mem_base) |
---|
| 139 | io_pp_set_reg_16 (cs, reg, data); |
---|
| 140 | else |
---|
| 141 | cs8900_mem_set_reg (cs, reg, data); |
---|
[a2117cd6] | 142 | } |
---|
[1f14ff4] | 143 | |
---|
[a2117cd6] | 144 | static inline void |
---|
[00bf7745] | 145 | mem_pp_bit_set_reg (cs8900_device *cs, unsigned short reg, unsigned short mask) |
---|
[a2117cd6] | 146 | { |
---|
[00bf7745] | 147 | if (!cs->mem_base) |
---|
| 148 | io_pp_bit_set_reg_16 (cs, reg, mask); |
---|
| 149 | else |
---|
| 150 | { |
---|
| 151 | rtems_interrupt_level level; |
---|
| 152 | rtems_interrupt_disable (level); |
---|
| 153 | mem_pp_set_reg (cs, reg, mem_pp_get_reg (cs, reg) | mask); |
---|
| 154 | rtems_interrupt_enable (level); |
---|
| 155 | } |
---|
[a2117cd6] | 156 | } |
---|
[1f14ff4] | 157 | |
---|
[a2117cd6] | 158 | static inline void |
---|
[00bf7745] | 159 | mem_pp_bit_clear_reg (cs8900_device *cs, unsigned short reg, unsigned short mask) |
---|
[a2117cd6] | 160 | { |
---|
[00bf7745] | 161 | if (!cs->mem_base) |
---|
| 162 | io_pp_bit_clear_reg_16 (cs, reg, mask); |
---|
| 163 | else |
---|
| 164 | { |
---|
| 165 | rtems_interrupt_level level; |
---|
| 166 | rtems_interrupt_disable (level); |
---|
| 167 | mem_pp_set_reg (cs, reg, mem_pp_get_reg (cs, reg) & ~mask); |
---|
| 168 | rtems_interrupt_enable (level); |
---|
| 169 | } |
---|
[1f14ff4] | 170 | } |
---|
| 171 | |
---|
[a2117cd6] | 172 | /* |
---|
| 173 | * Trace defines and control structures. |
---|
| 174 | */ |
---|
[00bf7745] | 175 | |
---|
[a2117cd6] | 176 | #define CS8900_T_INT (0) |
---|
| 177 | #define CS8900_T_RX_OK (1) |
---|
| 178 | #define CS8900_T_RX_DROPPED (2) |
---|
| 179 | #define CS8900_T_NO_MBUF (3) |
---|
| 180 | #define CS8900_T_NO_CLUSTERS (4) |
---|
| 181 | #define CS8900_T_RX_BEGIN (5) |
---|
| 182 | #define CS8900_T_RX_END (6) |
---|
| 183 | |
---|
| 184 | #if CS8900_TRACE |
---|
| 185 | |
---|
| 186 | static const char *cs8900_trace_labels[] = |
---|
[1f14ff4] | 187 | { |
---|
[a2117cd6] | 188 | "int", |
---|
| 189 | "rx ok", |
---|
| 190 | "rx dropped", |
---|
| 191 | "no mbuf", |
---|
| 192 | "no clusters", |
---|
| 193 | "rx begin", |
---|
| 194 | "rx end" |
---|
| 195 | }; |
---|
[1f14ff4] | 196 | |
---|
[a2117cd6] | 197 | /* |
---|
| 198 | * Assumes a micro-second timer such as the Coldfire. |
---|
| 199 | */ |
---|
[1f14ff4] | 200 | |
---|
[ee4f57d] | 201 | uint32_t rtems_read_timer (); |
---|
[1f14ff4] | 202 | |
---|
[a2117cd6] | 203 | static inline void |
---|
| 204 | cs8900_trace (cs8900_device *cs, unsigned short key, unsigned long var) |
---|
[1f14ff4] | 205 | { |
---|
[a2117cd6] | 206 | rtems_interrupt_level level; |
---|
[00bf7745] | 207 | |
---|
[a2117cd6] | 208 | rtems_interrupt_disable (level); |
---|
[00bf7745] | 209 | |
---|
[a2117cd6] | 210 | if (cs->trace_in < CS8900_TRACE_SIZE) |
---|
| 211 | { |
---|
| 212 | cs->trace_key[cs->trace_in] = key; |
---|
| 213 | cs->trace_var[cs->trace_in] = var; |
---|
| 214 | cs->trace_time[cs->trace_in] = rtems_read_timer (); |
---|
| 215 | cs->trace_in++; |
---|
| 216 | } |
---|
[00bf7745] | 217 | |
---|
[a2117cd6] | 218 | rtems_interrupt_enable (level); |
---|
| 219 | } |
---|
| 220 | #else |
---|
| 221 | #define cs8900_trace(c, k, v) |
---|
[1f14ff4] | 222 | #endif |
---|
| 223 | |
---|
[00bf7745] | 224 | void cs8900_get_mac_addr (cs8900_device *cs, unsigned char *mac_address) |
---|
| 225 | { |
---|
| 226 | unsigned short ma; |
---|
| 227 | |
---|
| 228 | /* |
---|
| 229 | * Only ever use IO calls for this function as it can be |
---|
| 230 | * called before memory mode has been enabled. |
---|
| 231 | */ |
---|
| 232 | |
---|
| 233 | ma = io_pp_get_reg_16 (cs, CS8900_PP_IA); |
---|
| 234 | mac_address[0] = ma >> 8; |
---|
| 235 | mac_address[1] = ma; |
---|
| 236 | |
---|
| 237 | ma = io_pp_get_reg_16 (cs, CS8900_PP_IA + 2); |
---|
| 238 | mac_address[2] = ma >> 8; |
---|
| 239 | mac_address[3] = ma; |
---|
| 240 | |
---|
| 241 | ma = io_pp_get_reg_16 (cs, CS8900_PP_IA + 4); |
---|
| 242 | mac_address[4] = ma >> 8; |
---|
| 243 | mac_address[5] = ma; |
---|
| 244 | } |
---|
| 245 | |
---|
[a2117cd6] | 246 | /* |
---|
| 247 | * Bring the chip online. |
---|
| 248 | */ |
---|
[1f14ff4] | 249 | |
---|
[a2117cd6] | 250 | static void |
---|
| 251 | cs8900_hardware_init (cs8900_device *cs) |
---|
[1f14ff4] | 252 | { |
---|
[a2117cd6] | 253 | unsigned long prod_id; |
---|
| 254 | unsigned short status; |
---|
| 255 | |
---|
| 256 | /* |
---|
| 257 | * Do nothing while the device is calibrating and checking the EEPROM. |
---|
| 258 | * We must wait 20msecs. |
---|
| 259 | */ |
---|
[00bf7745] | 260 | |
---|
| 261 | io_pp_bit_set_reg_16 (cs, CS8900_PP_SelfCTL, CS8900_SELF_CTRL_RESET); |
---|
[1f14ff4] | 262 | |
---|
[88c74ab] | 263 | rtems_task_wake_after (RTEMS_MILLISECONDS_TO_TICKS (20)); |
---|
[00bf7745] | 264 | |
---|
| 265 | status = io_pp_get_reg_16 (cs, CS8900_PP_SelfST); |
---|
[aae96a2] | 266 | if (status == 0) { |
---|
| 267 | printf("Reading status register again\n"); |
---|
[00bf7745] | 268 | status = io_pp_get_reg_16 (cs, CS8900_PP_SelfST); |
---|
[aae96a2] | 269 | } |
---|
[00bf7745] | 270 | |
---|
[a2117cd6] | 271 | if (((status & CS8900_SELF_STATUS_INITD) == 0) || |
---|
| 272 | ((status & CS8900_SELF_STATUS_INITD) && |
---|
| 273 | (status & CS8900_SELF_STATUS_EEPROM_PRESENT) && |
---|
| 274 | (status & CS8900_SELF_STATUS_SIBUST))) |
---|
[1f14ff4] | 275 | { |
---|
[a2117cd6] | 276 | printf ("CS8900: %s. Initialisation aborted.\n", |
---|
| 277 | (status & CS8900_SELF_STATUS_INITD) ? |
---|
| 278 | "EEPROM read/write failed to complete" : |
---|
[00bf7745] | 279 | "Failed to complete to reset"); |
---|
[a2117cd6] | 280 | return; |
---|
[1f14ff4] | 281 | } |
---|
[00bf7745] | 282 | |
---|
| 283 | /* Set the RX queue size if not set by the BSP. */ |
---|
| 284 | |
---|
| 285 | if (cs->rx_queue_size == 0) |
---|
| 286 | cs->rx_queue_size = 10; |
---|
| 287 | |
---|
[a2117cd6] | 288 | /* Probe the device for its ID */ |
---|
| 289 | |
---|
[00bf7745] | 290 | prod_id = io_pp_get_reg_32 (cs, CS8900_PP_PROD_ID); |
---|
[1f14ff4] | 291 | |
---|
[a2117cd6] | 292 | if ((prod_id >> 16) != CS8900_ESIA_ID) |
---|
[1f14ff4] | 293 | { |
---|
[00bf7745] | 294 | printf ("CS8900: Invalid EISA ID, read product code 0x%08lx\n", prod_id); |
---|
[a2117cd6] | 295 | return; |
---|
| 296 | } |
---|
| 297 | |
---|
| 298 | if ((prod_id & 0x000000ff) != 0) |
---|
| 299 | { |
---|
[00bf7745] | 300 | printf ("CS8900: Unsupported product id, read product code 0x%08lx\n", |
---|
[a2117cd6] | 301 | prod_id); |
---|
| 302 | return; |
---|
| 303 | } |
---|
| 304 | |
---|
| 305 | printf ("CS8900 Rev %ld, %s, %s.\n", |
---|
| 306 | (prod_id >> 8) & 0x1f, |
---|
| 307 | status & CS8900_SELF_STATUS_3_3_V ? "3.3V" : "5.0V", |
---|
| 308 | status & CS8900_SELF_STATUS_EEPROM_PRESENT ? |
---|
| 309 | "EEPROM present" : "no EEPROM"); |
---|
| 310 | |
---|
| 311 | /* |
---|
| 312 | * Switch to memory base accesses as they are faster. No indirect access. |
---|
| 313 | */ |
---|
[00bf7745] | 314 | |
---|
| 315 | if (cs->mem_base) |
---|
| 316 | { |
---|
| 317 | io_pp_set_reg_16 (cs, CS8900_PP_MEM_BASE, cs->mem_base); |
---|
| 318 | io_pp_set_reg_16 (cs, CS8900_PP_MEM_BASE + 2, (cs->mem_base >> 16) & 0xf); |
---|
| 319 | |
---|
| 320 | io_pp_set_reg_16 (cs, |
---|
| 321 | CS8900_PP_BusCTL, |
---|
| 322 | CS8900_BUS_CTRL_RESET_RX_DMA | |
---|
| 323 | CS8900_BUS_CTRL_USE_SA | |
---|
| 324 | CS8900_BUS_CTRL_MEMORY_ENABLE); |
---|
| 325 | io_pp_set_reg_16 (cs, |
---|
| 326 | CS8900_PP_BusCTL, |
---|
| 327 | CS8900_BUS_CTRL_USE_SA | |
---|
| 328 | CS8900_BUS_CTRL_MEMORY_ENABLE); |
---|
| 329 | } |
---|
[a2117cd6] | 330 | |
---|
| 331 | /* |
---|
| 332 | * We are now in memory mapped mode. |
---|
| 333 | */ |
---|
| 334 | |
---|
| 335 | /* |
---|
| 336 | * Program the Line Control register with the mode we want. |
---|
| 337 | * |
---|
| 338 | * No auto detect support at the moment. Only 10BaseT. |
---|
| 339 | */ |
---|
| 340 | |
---|
[00bf7745] | 341 | mem_pp_set_reg (cs, CS8900_PP_LineCFG, CS8900_LINE_CTRL_10BASET); |
---|
| 342 | |
---|
[a2117cd6] | 343 | /* |
---|
| 344 | * Ask the user for the MAC address, the program into the device. |
---|
| 345 | */ |
---|
| 346 | |
---|
| 347 | #define MACO(o) cs->arpcom.ac_enaddr[o] |
---|
[00bf7745] | 348 | |
---|
| 349 | mem_pp_set_reg (cs, CS8900_PP_IA, |
---|
[a2117cd6] | 350 | (((unsigned int) MACO (1)) << 8) | |
---|
| 351 | ((unsigned int) MACO (0))); |
---|
[00bf7745] | 352 | mem_pp_set_reg (cs, CS8900_PP_IA + 2, |
---|
[a2117cd6] | 353 | (((unsigned int) MACO (3)) << 8) | |
---|
| 354 | ((unsigned int) MACO (2))); |
---|
[00bf7745] | 355 | mem_pp_set_reg (cs, CS8900_PP_IA + 4, |
---|
[a2117cd6] | 356 | (((unsigned int) MACO (5)) << 8) | |
---|
| 357 | ((unsigned int) MACO (4))); |
---|
| 358 | |
---|
| 359 | /* |
---|
| 360 | * Set the Buffer configuration. |
---|
| 361 | */ |
---|
| 362 | |
---|
[00bf7745] | 363 | mem_pp_set_reg (cs, CS8900_PP_BufCFG, |
---|
[a2117cd6] | 364 | CS8900_BUFFER_CONFIG_RDY_FOR_TX | |
---|
| 365 | CS8900_BUFFER_CONFIG_TX_UNDERRUN | |
---|
| 366 | CS8900_BUFFER_CONFIG_TX_COL_OVF | |
---|
| 367 | CS8900_BUFFER_CONFIG_RX_MISSED_OVF); |
---|
| 368 | |
---|
| 369 | /* |
---|
| 370 | * Set the Receiver configuration. |
---|
| 371 | */ |
---|
| 372 | |
---|
[00bf7745] | 373 | mem_pp_set_reg (cs, CS8900_PP_RxCFG, |
---|
[a2117cd6] | 374 | CS8900_RX_CONFIG_RX_OK | |
---|
| 375 | CS8900_RX_CONFIG_CRC_ERROR | |
---|
| 376 | CS8900_RX_CONFIG_RUNT| |
---|
| 377 | CS8900_RX_CONFIG_EXTRA_DATA); |
---|
| 378 | |
---|
| 379 | /* |
---|
| 380 | * Set the Receiver control. |
---|
| 381 | */ |
---|
| 382 | |
---|
[00bf7745] | 383 | mem_pp_set_reg (cs, CS8900_PP_RxCTL, |
---|
[a2117cd6] | 384 | CS8900_RX_CTRL_RX_OK | |
---|
| 385 | CS8900_RX_CTRL_MULTICAST | |
---|
| 386 | CS8900_RX_CTRL_INDIVIDUAL | |
---|
| 387 | CS8900_RX_CTRL_BROADCAST); |
---|
[00bf7745] | 388 | |
---|
[a2117cd6] | 389 | /* |
---|
| 390 | * Set the Transmitter configuration. |
---|
| 391 | */ |
---|
| 392 | |
---|
[00bf7745] | 393 | mem_pp_set_reg (cs, CS8900_PP_TxCFG, |
---|
[a2117cd6] | 394 | CS8900_TX_CONFIG_TX_OK | |
---|
| 395 | CS8900_TX_CONFIG_OUT_OF_WINDOW | |
---|
| 396 | CS8900_TX_CONFIG_JABBER | |
---|
| 397 | CS8900_TX_CONFIG_16_COLLISION); |
---|
| 398 | |
---|
| 399 | /* |
---|
| 400 | * Attach the interrupt handler. |
---|
| 401 | */ |
---|
| 402 | |
---|
[00bf7745] | 403 | cs8900_attach_interrupt (cs); |
---|
| 404 | |
---|
[a2117cd6] | 405 | /* |
---|
| 406 | * Program the interrupt level we require then enable interrupts. |
---|
[00bf7745] | 407 | * |
---|
| 408 | * Note, this will need to change to support other levels. |
---|
[a2117cd6] | 409 | */ |
---|
| 410 | |
---|
[00bf7745] | 411 | mem_pp_set_reg (cs, CS8900_PP_INT, cs->irq_level & 3); |
---|
[a2117cd6] | 412 | |
---|
[00bf7745] | 413 | mem_pp_bit_set_reg (cs, CS8900_PP_BusCTL, |
---|
[a2117cd6] | 414 | CS8900_BUS_CTRL_ENABLE_INT); |
---|
[1f14ff4] | 415 | } |
---|
| 416 | |
---|
[a2117cd6] | 417 | rtems_isr |
---|
| 418 | cs8900_interrupt (rtems_vector_number v, void *csp) |
---|
[1f14ff4] | 419 | { |
---|
[a2117cd6] | 420 | cs8900_device *cs = csp; |
---|
| 421 | unsigned short isq = 0; |
---|
| 422 | struct mbuf *m; |
---|
| 423 | unsigned char *p; |
---|
| 424 | |
---|
| 425 | ++cs->eth_stats.interrupts; |
---|
| 426 | |
---|
| 427 | while (1) |
---|
| 428 | { |
---|
[00bf7745] | 429 | isq = mem_pp_get_reg (cs, CS8900_PP_ISQ); |
---|
[a2117cd6] | 430 | |
---|
| 431 | cs8900_trace (cs, CS8900_T_INT, isq); |
---|
| 432 | |
---|
| 433 | /* |
---|
| 434 | * No more interrupts to service. |
---|
| 435 | */ |
---|
| 436 | |
---|
| 437 | if (isq == 0) |
---|
| 438 | return; |
---|
[00bf7745] | 439 | |
---|
[a2117cd6] | 440 | switch (isq & 0x1f) |
---|
| 441 | { |
---|
| 442 | case 0x04: |
---|
| 443 | |
---|
| 444 | /* |
---|
| 445 | * RxEvent. |
---|
| 446 | */ |
---|
| 447 | |
---|
| 448 | ++cs->eth_stats.rx_interrupts; |
---|
| 449 | |
---|
| 450 | if (isq & CS8900_RX_EVENT_RX_OK) |
---|
| 451 | { |
---|
| 452 | m = cs->rx_ready_head; |
---|
| 453 | if (m) |
---|
| 454 | { |
---|
| 455 | cs->rx_ready_head = m->m_nextpkt; |
---|
| 456 | if (cs->rx_ready_head == 0) |
---|
| 457 | cs->rx_ready_tail = 0; |
---|
| 458 | m->m_nextpkt = 0; |
---|
| 459 | cs->rx_ready_len--; |
---|
[00bf7745] | 460 | |
---|
[a2117cd6] | 461 | p = mtod (m, unsigned char *); |
---|
[00bf7745] | 462 | |
---|
| 463 | m->m_pkthdr.len = cs8900_get_data_block (cs, p); |
---|
[a2117cd6] | 464 | |
---|
| 465 | if (cs->rx_loaded_tail == 0) |
---|
| 466 | cs->rx_loaded_head = m; |
---|
| 467 | else |
---|
| 468 | cs->rx_loaded_tail->m_nextpkt = m; |
---|
| 469 | cs->rx_loaded_tail = m; |
---|
| 470 | cs->rx_loaded_len++; |
---|
| 471 | |
---|
| 472 | if (cs->rx_loaded_len == 1) |
---|
| 473 | { |
---|
[00bf7745] | 474 | cs8900_trace (cs, CS8900_T_RX_OK, cs->rx_loaded_len); |
---|
[26e90fb1] | 475 | rtems_bsdnet_event_send (cs->rx_task, CS8900_RX_OK_EVENT); |
---|
[a2117cd6] | 476 | } |
---|
| 477 | } |
---|
| 478 | else |
---|
| 479 | { |
---|
| 480 | ++cs->eth_stats.rx_dropped; |
---|
[00bf7745] | 481 | |
---|
| 482 | cs8900_trace (cs, CS8900_T_RX_DROPPED, cs->rx_loaded_len); |
---|
[a2117cd6] | 483 | |
---|
| 484 | if (cs->rx_loaded_len == 0) |
---|
[26e90fb1] | 485 | rtems_bsdnet_event_send (cs->rx_task, CS8900_RX_OK_EVENT); |
---|
[a2117cd6] | 486 | } |
---|
| 487 | } |
---|
| 488 | else |
---|
| 489 | { |
---|
| 490 | if (isq & CS8900_RX_EVENT_CRC_ERROR) |
---|
| 491 | ++cs->eth_stats.rx_crc_errors; |
---|
| 492 | |
---|
| 493 | if (isq & CS8900_RX_EVENT_RUNT) |
---|
| 494 | ++cs->eth_stats.rx_runt_errors; |
---|
[00bf7745] | 495 | |
---|
[a2117cd6] | 496 | if (isq & CS8900_RX_EVENT_EXTRA_DATA) |
---|
| 497 | ++cs->eth_stats.rx_oversize_errors; |
---|
| 498 | } |
---|
| 499 | break; |
---|
| 500 | |
---|
| 501 | case 0x08: |
---|
[00bf7745] | 502 | |
---|
[a2117cd6] | 503 | /* |
---|
| 504 | * TxEvent. |
---|
| 505 | */ |
---|
| 506 | |
---|
| 507 | ++cs->eth_stats.tx_interrupts; |
---|
| 508 | |
---|
| 509 | if (cs->tx_active) |
---|
| 510 | { |
---|
| 511 | if (isq & CS8900_TX_EVENT_TX_OK) |
---|
| 512 | ++cs->eth_stats.tx_ok; |
---|
| 513 | |
---|
| 514 | cs->tx_active = 0; |
---|
[00bf7745] | 515 | |
---|
[26e90fb1] | 516 | rtems_bsdnet_event_send (cs->tx_task, CS8900_TX_OK_EVENT); |
---|
[a2117cd6] | 517 | } |
---|
| 518 | break; |
---|
| 519 | |
---|
| 520 | case 0x0c: |
---|
[00bf7745] | 521 | |
---|
[a2117cd6] | 522 | /* |
---|
| 523 | * BufEvent. |
---|
| 524 | */ |
---|
[00bf7745] | 525 | |
---|
[a2117cd6] | 526 | if (isq & CS8900_BUFFER_EVENT_RDY_FOR_TX) |
---|
| 527 | { |
---|
| 528 | if (cs->tx_active) |
---|
| 529 | { |
---|
| 530 | ++cs->eth_stats.tx_rdy4tx; |
---|
[26e90fb1] | 531 | rtems_bsdnet_event_send (cs->tx_task, CS8900_TX_WAIT_EVENT); |
---|
[a2117cd6] | 532 | } |
---|
| 533 | } |
---|
| 534 | else if (isq & CS8900_BUFFER_EVENT_TX_UNDERRUN) |
---|
| 535 | { |
---|
| 536 | ++cs->eth_stats.tx_underrun_errors; |
---|
| 537 | if (cs->tx_active) |
---|
[26e90fb1] | 538 | rtems_bsdnet_event_send (cs->tx_task, CS8900_TX_OK_EVENT); |
---|
[a2117cd6] | 539 | } |
---|
| 540 | else if (isq & CS8900_BUFFER_EVENT_SW_INT) |
---|
| 541 | { |
---|
| 542 | ++cs->eth_stats.int_swint_res; |
---|
| 543 | } |
---|
| 544 | break; |
---|
| 545 | |
---|
| 546 | case 0x10: |
---|
[00bf7745] | 547 | |
---|
[a2117cd6] | 548 | /* |
---|
| 549 | * RxMiss. |
---|
| 550 | */ |
---|
[00bf7745] | 551 | |
---|
[a2117cd6] | 552 | cs->eth_stats.rx_missed_errors += |
---|
[00bf7745] | 553 | mem_pp_get_reg (cs, CS8900_PP_RxMISS) >> 6; |
---|
[a2117cd6] | 554 | break; |
---|
[1f14ff4] | 555 | |
---|
[a2117cd6] | 556 | case 0x12: |
---|
[00bf7745] | 557 | |
---|
[a2117cd6] | 558 | /* |
---|
| 559 | * TxCol. |
---|
| 560 | */ |
---|
| 561 | |
---|
| 562 | cs->eth_stats.tx_collisions += |
---|
[00bf7745] | 563 | mem_pp_get_reg (cs, CS8900_PP_TxCol) >> 6; |
---|
[a2117cd6] | 564 | break; |
---|
| 565 | |
---|
| 566 | default: |
---|
| 567 | break; |
---|
| 568 | } |
---|
| 569 | } |
---|
[00bf7745] | 570 | |
---|
[a2117cd6] | 571 | } |
---|
| 572 | |
---|
| 573 | int |
---|
[00bf7745] | 574 | cs8900_link_active (cs8900_device *cs) |
---|
[a2117cd6] | 575 | { |
---|
[00bf7745] | 576 | return ((mem_pp_get_reg (cs, CS8900_PP_LineST) & CS8900_LINE_STATUS_LINK_OK) ? |
---|
[a2117cd6] | 577 | 1 : 0); |
---|
| 578 | } |
---|
| 579 | |
---|
| 580 | static inline void |
---|
| 581 | cs8900_rx_refill_queue (cs8900_device *cs) |
---|
| 582 | { |
---|
| 583 | struct ifnet *ifp = &cs->arpcom.ac_if; |
---|
| 584 | struct mbuf *m; |
---|
| 585 | rtems_interrupt_level level; |
---|
[00bf7745] | 586 | |
---|
[a2117cd6] | 587 | /* |
---|
| 588 | * Hold a single queue of mbuf's at the interface. This |
---|
| 589 | * will lower the latency of the driver. |
---|
| 590 | */ |
---|
| 591 | |
---|
[00bf7745] | 592 | while (cs->rx_ready_len < cs->rx_queue_size) |
---|
[1f14ff4] | 593 | { |
---|
[a2117cd6] | 594 | MGETHDR (m, M_DONTWAIT, MT_DATA); |
---|
[00bf7745] | 595 | |
---|
[a2117cd6] | 596 | if (!m) |
---|
| 597 | { |
---|
| 598 | ++cs->eth_stats.rx_no_mbufs; |
---|
[00bf7745] | 599 | cs8900_trace (cs, CS8900_T_NO_MBUF, cs->eth_stats.rx_no_mbufs); |
---|
[a2117cd6] | 600 | return; |
---|
| 601 | } |
---|
[00bf7745] | 602 | |
---|
[a2117cd6] | 603 | MCLGET (m, M_DONTWAIT); |
---|
[00bf7745] | 604 | |
---|
[a2117cd6] | 605 | if (!m->m_ext.ext_buf) |
---|
| 606 | { |
---|
| 607 | ++cs->eth_stats.rx_no_clusters; |
---|
[00bf7745] | 608 | cs8900_trace (cs, CS8900_T_NO_CLUSTERS, cs->eth_stats.rx_no_clusters); |
---|
[a2117cd6] | 609 | m_free (m); |
---|
| 610 | return; |
---|
| 611 | } |
---|
| 612 | m->m_pkthdr.rcvif = ifp; |
---|
| 613 | m->m_nextpkt = 0; |
---|
| 614 | |
---|
| 615 | rtems_interrupt_disable (level); |
---|
[00bf7745] | 616 | |
---|
[a2117cd6] | 617 | if (cs->rx_ready_tail == 0) |
---|
| 618 | cs->rx_ready_head = m; |
---|
| 619 | else |
---|
| 620 | cs->rx_ready_tail->m_nextpkt = m; |
---|
| 621 | cs->rx_ready_tail = m; |
---|
| 622 | cs->rx_ready_len++; |
---|
| 623 | |
---|
| 624 | rtems_interrupt_enable (level); |
---|
[1f14ff4] | 625 | } |
---|
[a2117cd6] | 626 | } |
---|
| 627 | |
---|
| 628 | static void |
---|
| 629 | cs8900_rx_task (void *arg) |
---|
| 630 | { |
---|
| 631 | cs8900_device *cs = arg; |
---|
| 632 | struct ifnet *ifp = &cs->arpcom.ac_if; |
---|
| 633 | rtems_event_set events; |
---|
| 634 | struct mbuf *m; |
---|
| 635 | struct ether_header *eh; |
---|
| 636 | rtems_status_code sc; |
---|
| 637 | rtems_interrupt_level level; |
---|
| 638 | |
---|
| 639 | /* |
---|
| 640 | * Turn the receiver and transmitter on. |
---|
| 641 | */ |
---|
[00bf7745] | 642 | |
---|
| 643 | mem_pp_bit_set_reg (cs, CS8900_PP_LineCFG, |
---|
[a2117cd6] | 644 | CS8900_LINE_CTRL_RX_ON | |
---|
| 645 | CS8900_LINE_CTRL_TX_ON); |
---|
[00bf7745] | 646 | |
---|
[a2117cd6] | 647 | /* |
---|
| 648 | * Start the software interrupt watchdog. |
---|
| 649 | */ |
---|
[00bf7745] | 650 | |
---|
| 651 | mem_pp_bit_set_reg (cs, CS8900_PP_BufCFG, |
---|
[a2117cd6] | 652 | CS8900_BUFFER_CONFIG_SW_INT); |
---|
| 653 | ++cs->eth_stats.int_swint_req; |
---|
[00bf7745] | 654 | |
---|
[a2117cd6] | 655 | /* |
---|
| 656 | * Loop reading packets. |
---|
| 657 | */ |
---|
[1f14ff4] | 658 | |
---|
[a2117cd6] | 659 | while (1) |
---|
[1f14ff4] | 660 | { |
---|
[a2117cd6] | 661 | cs8900_rx_refill_queue (cs); |
---|
[00bf7745] | 662 | |
---|
[a2117cd6] | 663 | sc = rtems_bsdnet_event_receive (CS8900_RX_OK_EVENT, |
---|
| 664 | RTEMS_WAIT | RTEMS_EVENT_ANY, |
---|
[88c74ab] | 665 | RTEMS_MILLISECONDS_TO_TICKS (250), |
---|
[a2117cd6] | 666 | &events); |
---|
| 667 | |
---|
| 668 | cs8900_rx_refill_queue (cs); |
---|
[00bf7745] | 669 | |
---|
[a2117cd6] | 670 | if (sc == RTEMS_TIMEOUT) |
---|
| 671 | { |
---|
| 672 | /* |
---|
| 673 | * We need to check the interrupt hardware in the cs8900a |
---|
| 674 | * has not locked up. It seems this occurs if the ISQ |
---|
| 675 | * queue fills up. |
---|
| 676 | * To test we generate a software interrupt and watch |
---|
| 677 | * a counter go up. If the counter does not go for 2 |
---|
| 678 | * software interrupts requests we flush the ISQ queue. |
---|
| 679 | */ |
---|
| 680 | |
---|
| 681 | if ((cs->eth_stats.int_swint_req - cs->eth_stats.int_swint_res) > 1) |
---|
| 682 | { |
---|
| 683 | printf ("cs8900: int lockup, isq flush\n"); |
---|
| 684 | |
---|
[00bf7745] | 685 | mem_pp_bit_clear_reg (cs, CS8900_PP_BusCTL, |
---|
[a2117cd6] | 686 | CS8900_BUS_CTRL_ENABLE_INT); |
---|
[00bf7745] | 687 | |
---|
| 688 | while (mem_pp_get_reg (cs, CS8900_PP_ISQ) != 0); |
---|
| 689 | |
---|
[a2117cd6] | 690 | cs->eth_stats.int_swint_req = cs->eth_stats.int_swint_res = 0; |
---|
| 691 | ++cs->eth_stats.int_lockup; |
---|
[00bf7745] | 692 | |
---|
| 693 | mem_pp_bit_set_reg (cs, CS8900_PP_BusCTL, |
---|
[a2117cd6] | 694 | CS8900_BUS_CTRL_ENABLE_INT); |
---|
| 695 | } |
---|
[00bf7745] | 696 | |
---|
| 697 | mem_pp_bit_set_reg (cs, CS8900_PP_BufCFG, |
---|
[a2117cd6] | 698 | CS8900_BUFFER_CONFIG_SW_INT); |
---|
| 699 | ++cs->eth_stats.int_swint_req; |
---|
| 700 | } |
---|
[1f14ff4] | 701 | |
---|
[a2117cd6] | 702 | cs8900_trace (cs, CS8900_T_RX_BEGIN, cs->rx_loaded_len); |
---|
[00bf7745] | 703 | |
---|
[a2117cd6] | 704 | while (cs->rx_loaded_len) |
---|
| 705 | { |
---|
| 706 | rtems_interrupt_disable (level); |
---|
[00bf7745] | 707 | |
---|
[a2117cd6] | 708 | m = cs->rx_loaded_head; |
---|
| 709 | if (m) |
---|
| 710 | { |
---|
| 711 | cs->rx_loaded_head = m->m_nextpkt; |
---|
| 712 | if (cs->rx_loaded_head == 0) |
---|
| 713 | cs->rx_loaded_tail = 0; |
---|
| 714 | m->m_nextpkt = 0; |
---|
| 715 | cs->rx_loaded_len--; |
---|
[00bf7745] | 716 | |
---|
[a2117cd6] | 717 | rtems_interrupt_enable (level); |
---|
[00bf7745] | 718 | |
---|
[a2117cd6] | 719 | m->m_pkthdr.rcvif = ifp; |
---|
[00bf7745] | 720 | |
---|
[a2117cd6] | 721 | cs->eth_stats.rx_bytes += m->m_pkthdr.len; |
---|
[00bf7745] | 722 | |
---|
[a2117cd6] | 723 | m->m_len = m->m_pkthdr.len = m->m_pkthdr.len - sizeof (struct ether_header); |
---|
[00bf7745] | 724 | |
---|
[a2117cd6] | 725 | eh = mtod (m, struct ether_header *); |
---|
| 726 | m->m_data += sizeof (struct ether_header); |
---|
[00bf7745] | 727 | |
---|
[a2117cd6] | 728 | ++cs->eth_stats.rx_packets; |
---|
[00bf7745] | 729 | |
---|
[a2117cd6] | 730 | ether_input (ifp, eh, m); |
---|
| 731 | } |
---|
| 732 | else |
---|
| 733 | { |
---|
| 734 | rtems_interrupt_enable (level); |
---|
| 735 | } |
---|
| 736 | } |
---|
| 737 | cs8900_trace (cs, CS8900_T_RX_END, cs->rx_loaded_len); |
---|
| 738 | } |
---|
[1f14ff4] | 739 | } |
---|
| 740 | |
---|
[a2117cd6] | 741 | static void |
---|
| 742 | cs8900_tx_task (void *arg) |
---|
[1f14ff4] | 743 | { |
---|
[a2117cd6] | 744 | cs8900_device *cs = arg; |
---|
| 745 | struct ifnet *ifp = &cs->arpcom.ac_if; |
---|
| 746 | rtems_event_set events; |
---|
| 747 | struct mbuf *m; |
---|
| 748 | rtems_status_code sc; |
---|
| 749 | |
---|
| 750 | /* |
---|
| 751 | * Wait for the link to come up. |
---|
| 752 | */ |
---|
| 753 | |
---|
[88c74ab] | 754 | rtems_task_wake_after (RTEMS_MILLISECONDS_TO_TICKS (750)); |
---|
[a2117cd6] | 755 | |
---|
| 756 | /* |
---|
| 757 | * Loop processing the tx queue. |
---|
| 758 | */ |
---|
| 759 | |
---|
| 760 | while (1) |
---|
[1f14ff4] | 761 | { |
---|
| 762 | /* |
---|
[a2117cd6] | 763 | * Fetch the mbuf list from the interface's queue. |
---|
[1f14ff4] | 764 | */ |
---|
| 765 | |
---|
[a2117cd6] | 766 | IF_DEQUEUE (&ifp->if_snd, m); |
---|
[1f14ff4] | 767 | |
---|
[a2117cd6] | 768 | /* |
---|
| 769 | * If something actually is present send it. |
---|
| 770 | */ |
---|
| 771 | |
---|
| 772 | if (!m) |
---|
[1f14ff4] | 773 | { |
---|
[a2117cd6] | 774 | ifp->if_flags &= ~IFF_OACTIVE; |
---|
| 775 | |
---|
| 776 | rtems_bsdnet_event_receive (CS8900_TX_START_EVENT, |
---|
| 777 | RTEMS_WAIT | RTEMS_EVENT_ANY, |
---|
| 778 | RTEMS_NO_TIMEOUT, |
---|
| 779 | &events); |
---|
| 780 | } |
---|
| 781 | else |
---|
| 782 | { |
---|
[00bf7745] | 783 | if (cs8900_link_active (cs)) |
---|
[1f14ff4] | 784 | { |
---|
[a2117cd6] | 785 | int resending; |
---|
[00bf7745] | 786 | |
---|
[a2117cd6] | 787 | do |
---|
| 788 | { |
---|
| 789 | unsigned short buf_status; |
---|
| 790 | |
---|
| 791 | resending = 0; |
---|
[00bf7745] | 792 | |
---|
[a2117cd6] | 793 | cs->tx_active = 1; |
---|
[00bf7745] | 794 | |
---|
| 795 | mem_pp_set_reg (cs, CS8900_PP_TxCMD, |
---|
[a2117cd6] | 796 | CS8900_TX_CMD_STATUS_TX_START_ENTIRE | |
---|
| 797 | CS8900_TX_CMD_STATUS_FORCE); |
---|
[00bf7745] | 798 | mem_pp_set_reg (cs, CS8900_PP_TxLength, m->m_pkthdr.len); |
---|
| 799 | |
---|
| 800 | buf_status = mem_pp_get_reg (cs, CS8900_PP_BusST); |
---|
[a2117cd6] | 801 | |
---|
| 802 | /* |
---|
| 803 | * If the bid for memory in the device fails trash the |
---|
| 804 | * transmit and try again next time. |
---|
| 805 | */ |
---|
[1f14ff4] | 806 | |
---|
[a2117cd6] | 807 | if (buf_status & CS8900_BUS_STATUS_TX_BID_ERROR) |
---|
| 808 | ++cs->eth_stats.tx_bid_errors; |
---|
| 809 | else |
---|
| 810 | { |
---|
| 811 | /* |
---|
| 812 | * If the buffer is not read enable the interrupt and then wait. |
---|
| 813 | */ |
---|
[00bf7745] | 814 | |
---|
[a2117cd6] | 815 | if ((buf_status & CS8900_BUS_STATUS_RDY_FOR_TX_NOW) == 0) |
---|
| 816 | { |
---|
| 817 | cs->eth_stats.tx_wait_for_rdy4tx++; |
---|
| 818 | sc = rtems_bsdnet_event_receive (CS8900_TX_WAIT_EVENT, |
---|
| 819 | RTEMS_WAIT | RTEMS_EVENT_ANY, |
---|
[88c74ab] | 820 | RTEMS_MILLISECONDS_TO_TICKS (750), |
---|
[a2117cd6] | 821 | &events); |
---|
| 822 | if (sc == RTEMS_TIMEOUT) |
---|
| 823 | { |
---|
| 824 | /* |
---|
| 825 | * For some reason the wait request has been dropped, |
---|
| 826 | * so lets resend from the start. |
---|
| 827 | */ |
---|
| 828 | |
---|
| 829 | printf ("tx resend\n"); |
---|
| 830 | ++cs->eth_stats.tx_resends; |
---|
| 831 | resending = 1; |
---|
| 832 | } |
---|
| 833 | } |
---|
| 834 | |
---|
| 835 | if (!resending) |
---|
| 836 | { |
---|
[00bf7745] | 837 | cs8900_tx_load (cs, m); |
---|
[a2117cd6] | 838 | cs->eth_stats.tx_packets++; |
---|
| 839 | cs->eth_stats.tx_bytes += m->m_pkthdr.len; |
---|
| 840 | } |
---|
| 841 | } |
---|
| 842 | } |
---|
| 843 | while (resending); |
---|
[00bf7745] | 844 | |
---|
[a2117cd6] | 845 | m_freem (m); |
---|
[00bf7745] | 846 | |
---|
[a2117cd6] | 847 | do |
---|
| 848 | { |
---|
| 849 | rtems_bsdnet_event_receive (CS8900_TX_OK_EVENT, |
---|
| 850 | RTEMS_WAIT | RTEMS_EVENT_ANY, |
---|
| 851 | RTEMS_NO_TIMEOUT, |
---|
| 852 | &events); |
---|
| 853 | } |
---|
| 854 | while (cs->tx_active); |
---|
| 855 | } |
---|
| 856 | else |
---|
[1f14ff4] | 857 | { |
---|
[a2117cd6] | 858 | ++cs->eth_stats.tx_dropped; |
---|
| 859 | m_freem (m); |
---|
[1f14ff4] | 860 | } |
---|
[a2117cd6] | 861 | } |
---|
| 862 | } |
---|
| 863 | } |
---|
| 864 | |
---|
| 865 | static void |
---|
| 866 | cs8900_start (struct ifnet *ifp) |
---|
| 867 | { |
---|
| 868 | cs8900_device *cs = ifp->if_softc; |
---|
| 869 | |
---|
| 870 | /* |
---|
| 871 | * Tell the transmit daemon to wake up and send a packet. |
---|
| 872 | */ |
---|
| 873 | |
---|
| 874 | ifp->if_flags |= IFF_OACTIVE; |
---|
| 875 | |
---|
[26e90fb1] | 876 | rtems_bsdnet_event_send (cs->tx_task, CS8900_TX_START_EVENT); |
---|
[a2117cd6] | 877 | } |
---|
| 878 | |
---|
| 879 | static void |
---|
| 880 | cs8900_stop (cs8900_device *cs) |
---|
| 881 | { |
---|
[00bf7745] | 882 | mem_pp_bit_clear_reg (cs, CS8900_PP_LineCFG, |
---|
[a2117cd6] | 883 | CS8900_LINE_CTRL_RX_ON | |
---|
| 884 | CS8900_LINE_CTRL_TX_ON); |
---|
[00bf7745] | 885 | |
---|
| 886 | mem_pp_bit_clear_reg (cs, CS8900_PP_BusCTL, |
---|
[a2117cd6] | 887 | CS8900_BUS_CTRL_ENABLE_INT); |
---|
| 888 | } |
---|
| 889 | |
---|
| 890 | static const char *eth_statistics_labels[] = |
---|
| 891 | { |
---|
| 892 | "rx packets", |
---|
| 893 | "tx packets", |
---|
| 894 | "rx bytes", |
---|
| 895 | "tx bytes", |
---|
| 896 | "rx interrupts", |
---|
| 897 | "tx interrupts", |
---|
| 898 | "rx dropped", |
---|
| 899 | "rx no mbuf", |
---|
| 900 | "rx no custers", |
---|
| 901 | "rx oversize errors", |
---|
| 902 | "rx crc errors", |
---|
| 903 | "rx runt errors", |
---|
| 904 | "rx missed errors", |
---|
| 905 | "tx ok", |
---|
| 906 | "tx collisions", |
---|
| 907 | "tx bid errors", |
---|
| 908 | "tx wait for rdy4tx", |
---|
| 909 | "tx rdy4tx", |
---|
| 910 | "tx underrun errors", |
---|
| 911 | "tx dropped", |
---|
| 912 | "tx resends", |
---|
| 913 | "int swint req", |
---|
| 914 | "int swint res", |
---|
| 915 | "int lockup", |
---|
| 916 | "interrupts" |
---|
| 917 | }; |
---|
| 918 | |
---|
| 919 | static void |
---|
| 920 | cs8900_stats (cs8900_device *cs) |
---|
| 921 | { |
---|
| 922 | int i; |
---|
| 923 | int max_label = 0; |
---|
| 924 | int len; |
---|
| 925 | unsigned long *value = (unsigned long*) &cs->eth_stats.rx_packets; |
---|
| 926 | |
---|
| 927 | cs->eth_stats.rx_missed_errors += |
---|
[00bf7745] | 928 | mem_pp_get_reg (cs, CS8900_PP_RxMISS) >> 6; |
---|
| 929 | |
---|
[a2117cd6] | 930 | cs->eth_stats.tx_collisions += |
---|
[00bf7745] | 931 | mem_pp_get_reg (cs, CS8900_PP_TxCol) >> 6; |
---|
| 932 | |
---|
[a2117cd6] | 933 | printf ("Network Driver Stats for CS8900 :\n"); |
---|
| 934 | |
---|
| 935 | for (i = 0; i < (sizeof (eth_statistics_labels) / sizeof (const char *)); i++) |
---|
| 936 | { |
---|
| 937 | len = strlen (eth_statistics_labels[i]); |
---|
| 938 | if (len > max_label) |
---|
| 939 | max_label = len; |
---|
| 940 | } |
---|
| 941 | |
---|
| 942 | max_label += 2; |
---|
| 943 | |
---|
| 944 | printf ("%*s - %10u %*s - %10u\n", |
---|
| 945 | max_label, "rx ready len", cs->rx_ready_len, |
---|
| 946 | max_label, "rx loaded len", cs->rx_loaded_len); |
---|
[00bf7745] | 947 | |
---|
[a2117cd6] | 948 | for (i = 0; |
---|
| 949 | i < (sizeof (eth_statistics_labels) / sizeof (const char *)); |
---|
| 950 | i++) |
---|
| 951 | { |
---|
| 952 | printf ("%*s - %10lu", |
---|
| 953 | max_label, eth_statistics_labels[i], value[i]); |
---|
[00bf7745] | 954 | |
---|
[a2117cd6] | 955 | i++; |
---|
[00bf7745] | 956 | |
---|
[a2117cd6] | 957 | if (i < (sizeof (eth_statistics_labels) / sizeof (const char *))) |
---|
| 958 | printf (" %*s - %10lu", |
---|
| 959 | max_label, eth_statistics_labels[i], value[i]); |
---|
| 960 | printf ("\n"); |
---|
[1f14ff4] | 961 | } |
---|
| 962 | |
---|
[a2117cd6] | 963 | #if CS8900_TRACE |
---|
[00bf7745] | 964 | |
---|
[a2117cd6] | 965 | for (i = 0; i < cs->trace_in; i++) |
---|
[1f14ff4] | 966 | { |
---|
[a2117cd6] | 967 | printf ("%8ld.%03ld ", cs->trace_time[i] / 1000, cs->trace_time[i] % 1000); |
---|
[00bf7745] | 968 | |
---|
[a2117cd6] | 969 | if (cs->trace_key[i] < sizeof (cs8900_trace_labels) / sizeof (char*)) |
---|
| 970 | printf ("%s : ", cs8900_trace_labels[cs->trace_key[i]]); |
---|
| 971 | else |
---|
| 972 | printf ("unknown trace key, %d : ", cs->trace_key[i]); |
---|
| 973 | |
---|
| 974 | if (cs->trace_key[i] == CS8900_T_INT) |
---|
| 975 | { |
---|
| 976 | printf ("0x%04lx ", cs->trace_var[i]); |
---|
| 977 | if (cs->trace_var[i] == 0) |
---|
| 978 | printf ("end"); |
---|
| 979 | else |
---|
| 980 | { |
---|
| 981 | switch (cs->trace_var[i] & 0x1f) |
---|
| 982 | { |
---|
| 983 | case 0x04: |
---|
| 984 | printf ("rx event"); |
---|
| 985 | break; |
---|
| 986 | |
---|
| 987 | case 0x08: |
---|
| 988 | printf ("tx event"); |
---|
| 989 | break; |
---|
| 990 | |
---|
| 991 | case 0x0c: |
---|
| 992 | printf ("buffer event"); |
---|
| 993 | break; |
---|
| 994 | |
---|
| 995 | case 0x10: |
---|
| 996 | printf ("rx missed"); |
---|
| 997 | break; |
---|
| 998 | |
---|
| 999 | case 0x12: |
---|
| 1000 | printf ("tx collisions"); |
---|
| 1001 | break; |
---|
| 1002 | |
---|
| 1003 | case 0x1f: |
---|
| 1004 | printf ("tx request"); |
---|
| 1005 | break; |
---|
[00bf7745] | 1006 | |
---|
[a2117cd6] | 1007 | case 0x1e: |
---|
| 1008 | printf ("tx wait 4 tx"); |
---|
| 1009 | break; |
---|
[00bf7745] | 1010 | |
---|
[a2117cd6] | 1011 | case 0x1d: |
---|
| 1012 | printf ("tx already active"); |
---|
| 1013 | break; |
---|
[00bf7745] | 1014 | |
---|
[a2117cd6] | 1015 | default: |
---|
| 1016 | printf ("unknown event"); |
---|
| 1017 | break; |
---|
| 1018 | } |
---|
| 1019 | } |
---|
| 1020 | } |
---|
| 1021 | else |
---|
| 1022 | printf ("0x%08lx", cs->trace_var[i]); |
---|
[00bf7745] | 1023 | |
---|
[a2117cd6] | 1024 | printf ("\n"); |
---|
[1f14ff4] | 1025 | } |
---|
[a2117cd6] | 1026 | |
---|
| 1027 | cs->trace_in = 0; |
---|
[00bf7745] | 1028 | |
---|
[a2117cd6] | 1029 | #endif |
---|
[1f14ff4] | 1030 | } |
---|
| 1031 | |
---|
[a2117cd6] | 1032 | static void |
---|
| 1033 | cs8900_init (void *arg) |
---|
[1f14ff4] | 1034 | { |
---|
[a2117cd6] | 1035 | cs8900_device *cs = arg; |
---|
| 1036 | struct ifnet *ifp = &cs->arpcom.ac_if; |
---|
| 1037 | |
---|
| 1038 | if (cs->rx_task == 0) |
---|
| 1039 | { |
---|
| 1040 | |
---|
| 1041 | /* |
---|
| 1042 | * Set up the hardware. |
---|
| 1043 | */ |
---|
[00bf7745] | 1044 | |
---|
[a2117cd6] | 1045 | cs8900_hardware_init (cs); |
---|
| 1046 | |
---|
| 1047 | /* |
---|
| 1048 | * Start driver task. We have only one task. |
---|
| 1049 | */ |
---|
[00bf7745] | 1050 | |
---|
[a2117cd6] | 1051 | cs->rx_task = rtems_bsdnet_newproc ("CSr0", 4096, cs8900_rx_task, cs); |
---|
| 1052 | cs->tx_task = rtems_bsdnet_newproc ("CSt0", 4096, cs8900_tx_task, cs); |
---|
| 1053 | } |
---|
| 1054 | |
---|
| 1055 | #ifdef todo |
---|
| 1056 | /* |
---|
| 1057 | * Set flags appropriately |
---|
| 1058 | */ |
---|
| 1059 | if (ifp->if_flags & IFF_PROMISC) |
---|
| 1060 | else |
---|
| 1061 | #endif |
---|
[00bf7745] | 1062 | |
---|
[a2117cd6] | 1063 | /* |
---|
| 1064 | * Tell the world that we're running. |
---|
| 1065 | */ |
---|
[00bf7745] | 1066 | |
---|
[a2117cd6] | 1067 | ifp->if_flags |= IFF_RUNNING; |
---|
| 1068 | |
---|
| 1069 | /* |
---|
[00bf7745] | 1070 | * Set the Line Control to bring the receive and transmitter online. |
---|
[a2117cd6] | 1071 | */ |
---|
| 1072 | |
---|
[00bf7745] | 1073 | mem_pp_bit_set_reg (cs, CS8900_PP_LineCFG, |
---|
[a2117cd6] | 1074 | CS8900_LINE_CTRL_RX_ON | |
---|
| 1075 | CS8900_LINE_CTRL_TX_ON); |
---|
| 1076 | |
---|
[00bf7745] | 1077 | mem_pp_bit_set_reg (cs, CS8900_PP_BusCTL, |
---|
[a2117cd6] | 1078 | CS8900_BUS_CTRL_ENABLE_INT); |
---|
[1f14ff4] | 1079 | } |
---|
| 1080 | |
---|
[a2117cd6] | 1081 | static int |
---|
[a612b50] | 1082 | cs8900_ioctl (struct ifnet *ifp, ioctl_command_t cmd, caddr_t data) |
---|
[1f14ff4] | 1083 | { |
---|
[a2117cd6] | 1084 | cs8900_device *cs = ifp->if_softc; |
---|
| 1085 | int error = 0; |
---|
| 1086 | |
---|
| 1087 | switch (cmd) |
---|
| 1088 | { |
---|
| 1089 | case SIOCGIFADDR: |
---|
| 1090 | case SIOCSIFADDR: |
---|
[00bf7745] | 1091 | |
---|
[a2117cd6] | 1092 | error = ether_ioctl (ifp, cmd, data); |
---|
| 1093 | break; |
---|
| 1094 | |
---|
| 1095 | case SIOCSIFFLAGS: |
---|
[00bf7745] | 1096 | |
---|
[a2117cd6] | 1097 | switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) |
---|
| 1098 | { |
---|
| 1099 | case IFF_RUNNING: |
---|
[00bf7745] | 1100 | |
---|
[a2117cd6] | 1101 | cs8900_stop (cs); |
---|
| 1102 | break; |
---|
| 1103 | |
---|
| 1104 | case IFF_UP: |
---|
[00bf7745] | 1105 | |
---|
[a2117cd6] | 1106 | cs8900_init (cs); |
---|
| 1107 | break; |
---|
| 1108 | |
---|
| 1109 | case IFF_UP | IFF_RUNNING: |
---|
[00bf7745] | 1110 | |
---|
[a2117cd6] | 1111 | cs8900_stop (cs); |
---|
| 1112 | cs8900_init (cs); |
---|
| 1113 | break; |
---|
| 1114 | |
---|
| 1115 | default: |
---|
| 1116 | break; |
---|
| 1117 | } |
---|
| 1118 | break; |
---|
| 1119 | |
---|
| 1120 | case SIO_RTEMS_SHOW_STATS: |
---|
[00bf7745] | 1121 | |
---|
[a2117cd6] | 1122 | cs8900_stats (cs); |
---|
| 1123 | break; |
---|
| 1124 | |
---|
| 1125 | /* FIXME: Multicast commands must be added here. */ |
---|
| 1126 | |
---|
| 1127 | default: |
---|
| 1128 | error = EINVAL; |
---|
| 1129 | break; |
---|
| 1130 | } |
---|
| 1131 | |
---|
| 1132 | return error; |
---|
[1f14ff4] | 1133 | } |
---|
| 1134 | |
---|
[a2117cd6] | 1135 | int |
---|
| 1136 | cs8900_driver_attach (struct rtems_bsdnet_ifconfig *config, int attaching) |
---|
[1f14ff4] | 1137 | { |
---|
[a2117cd6] | 1138 | cs8900_device *cs; |
---|
| 1139 | struct ifnet *ifp; |
---|
| 1140 | int mtu; |
---|
| 1141 | int unit; |
---|
| 1142 | char *name; |
---|
| 1143 | |
---|
| 1144 | /* |
---|
| 1145 | * Parse driver name |
---|
| 1146 | */ |
---|
[00bf7745] | 1147 | |
---|
[a2117cd6] | 1148 | if ((unit = rtems_bsdnet_parse_driver_name (config, &name)) < 0) |
---|
| 1149 | return 0; |
---|
[00bf7745] | 1150 | |
---|
| 1151 | cs = config->drv_ctrl; |
---|
[a2117cd6] | 1152 | cs->dev = unit; |
---|
| 1153 | ifp = &cs->arpcom.ac_if; |
---|
| 1154 | |
---|
| 1155 | if (attaching) |
---|
| 1156 | { |
---|
| 1157 | if (ifp->if_softc) |
---|
| 1158 | { |
---|
| 1159 | printf ("Driver `%s' already in use.\n", config->name); |
---|
| 1160 | return 0; |
---|
| 1161 | } |
---|
| 1162 | |
---|
| 1163 | /* |
---|
| 1164 | * Process options |
---|
| 1165 | */ |
---|
[00bf7745] | 1166 | |
---|
[a2117cd6] | 1167 | if (config->hardware_address) |
---|
| 1168 | memcpy (cs->arpcom.ac_enaddr, config->hardware_address, ETHER_ADDR_LEN); |
---|
| 1169 | else |
---|
[00bf7745] | 1170 | cs8900_get_mac_addr (cs, cs->arpcom.ac_enaddr); |
---|
| 1171 | |
---|
[a2117cd6] | 1172 | if (config->mtu) |
---|
| 1173 | mtu = config->mtu; |
---|
| 1174 | else |
---|
| 1175 | mtu = ETHERMTU; |
---|
[00bf7745] | 1176 | |
---|
[a2117cd6] | 1177 | cs->accept_bcast = !config->ignore_broadcast; |
---|
[00bf7745] | 1178 | |
---|
[a2117cd6] | 1179 | /* |
---|
| 1180 | * Set up network interface values. |
---|
| 1181 | */ |
---|
[00bf7745] | 1182 | |
---|
[a2117cd6] | 1183 | ifp->if_softc = cs; |
---|
| 1184 | ifp->if_unit = unit; |
---|
| 1185 | ifp->if_name = name; |
---|
| 1186 | ifp->if_mtu = mtu; |
---|
| 1187 | ifp->if_init = cs8900_init; |
---|
| 1188 | ifp->if_ioctl = cs8900_ioctl; |
---|
| 1189 | ifp->if_start = cs8900_start; |
---|
| 1190 | ifp->if_output = ether_output; |
---|
| 1191 | ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX; |
---|
[00bf7745] | 1192 | |
---|
[a2117cd6] | 1193 | if (ifp->if_snd.ifq_maxlen == 0) |
---|
| 1194 | ifp->if_snd.ifq_maxlen = ifqmaxlen; |
---|
[00bf7745] | 1195 | |
---|
[a2117cd6] | 1196 | /* |
---|
| 1197 | * Attach the interface to the stack. |
---|
| 1198 | */ |
---|
[00bf7745] | 1199 | |
---|
[a2117cd6] | 1200 | if_attach (ifp); |
---|
| 1201 | ether_ifattach (ifp); |
---|
| 1202 | } |
---|
| 1203 | else |
---|
| 1204 | { |
---|
| 1205 | if (!ifp->if_softc) |
---|
| 1206 | { |
---|
| 1207 | printf ("Driver `%s' not found.\n", config->name); |
---|
| 1208 | return 0; |
---|
| 1209 | } |
---|
| 1210 | |
---|
| 1211 | cs8900_stop (cs); |
---|
[00bf7745] | 1212 | cs8900_detach_interrupt (cs); |
---|
[a2117cd6] | 1213 | } |
---|
[00bf7745] | 1214 | |
---|
[a2117cd6] | 1215 | return 1; |
---|
[1f14ff4] | 1216 | } |
---|