bcm-net.c (20548B)
1 /* 2 * 3 * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file. 4 * 5 * Copyright 2007-2019 Broadcom Inc. All rights reserved. 6 */ 7 8 /* 9 * This version of the BCM Linux network driver is written 10 * to run on top of the linux-bcm-core module. 11 * 12 * All TX packets are tagged and all RX packets are assumed to 13 * include a tag (which is stripped unconditionally.) 14 * 15 * It is possible to segment the switch ports into multiple network 16 * devices by specifying port masks for each network device. 17 * 18 * For a list of supported module parameters, please see below. 19 */ 20 21 #include <gmodule.h> /* Must be included first */ 22 #include <linux/netdevice.h> 23 #include <linux/etherdevice.h> 24 #include <linux/random.h> 25 #include <sal/core/dpc.h> 26 #include <sal/appl/sal.h> 27 28 #include <soc/types.h> 29 #include <soc/enet.h> 30 #include <soc/drv.h> 31 32 #include <bcm/error.h> 33 #include <bcm/tx.h> 34 #include <bcm/rx.h> 35 #include <bcm/l2.h> 36 #include <bcm/stat.h> 37 #include <bcm/port.h> 38 39 #include <ibde.h> 40 #include <linux-bde.h> 41 #include <bcm-core.h> 42 43 44 MODULE_AUTHOR("Broadcom Corporation"); 45 MODULE_DESCRIPTION("Network Device Driver for BCM Core devices"); 46 MODULE_LICENSE("Proprietary"); 47 48 static int unit; 49 LKM_MOD_PARAM(unit, "i", int, 0); 50 MODULE_PARM_DESC(unit, 51 "SOC unit to operate on (default 0)"); 52 53 static int vlan = 1; 54 LKM_MOD_PARAM(vlan, "i", int, 0); 55 MODULE_PARM_DESC(vlan, 56 "VLAN ID used for transmission (default 1)"); 57 58 static char *mac_addr = NULL; 59 LKM_MOD_PARAM(mac_addr, "s", charp, 0); 60 MODULE_PARM_DESC(mac_addr, 61 "Ethernet MAC address (default 02:10:18:xx:xx:xx)"); 62 63 static int tx_buffers = 32; 64 LKM_MOD_PARAM(tx_buffers, "i", int, 0); 65 MODULE_PARM_DESC(tx_buffers, 66 "Number of preallocated TX packet buffers (default 32)"); 67 68 69 /* Module Information */ 70 #define MODULE_MAJOR 123 71 #define MODULE_NAME "linux-bcm-net" 72 73 /* Compatibility */ 74 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,27) 75 static inline void *netdev_priv(struct net_device *dev) 76 { 77 return dev->priv; 78 } 79 #endif /* KERNEL_VERSION(2,4,27) */ 80 81 /* 82 * Currently we cannot send packets from interrupt context because 83 * bcm_l2_addr_get will try to sleep while doing S-Channel messaging. 84 * To ensure we only send packets from process context, we pass all 85 * packets to an internal thread, which handles the actual packet 86 * transmissions. 87 */ 88 #define BNET_TX_THREAD 89 90 91 /* Local packet info */ 92 typedef struct pkt_info_s { 93 struct list_head list; 94 95 unsigned char *pkt; 96 bcm_pkt_t bcm_pkt; 97 98 int count; 99 } pkt_info_t; 100 101 typedef struct { 102 uint32_t pmask; 103 struct net_device *ndev; 104 struct net_device_stats stats; 105 pbmp_t pbmp; 106 } bnet_dev_t; 107 108 /* Default random MAC address has Broadcom OUI with local admin bit set */ 109 static sal_mac_addr_t bnet_dev_mac = { 0x02, 0x10, 0x18, 0x00, 0x00, 0x00 }; 110 111 static spinlock_t packet_lock; 112 113 /* 114 * Driver net device 115 * 116 * By default a separate network device will be assigned to port 0 117 * while the remaining ports will all belong to another network 118 * device. 119 */ 120 static bnet_dev_t bnet_dev[] = { 121 { 0x00000001 }, /* Port bitmask for 1st interface (ethX) */ 122 { 0xFFFFFFFE }, /* Port bitmask for 2nd interface (ethX+1) */ 123 { 0 } /* Last entry must be zero */ 124 }; 125 126 /* Driver Proc Entry root */ 127 static struct proc_dir_entry *bnet_proc_root = NULL; 128 129 /* Driver Proc Entry switch stats root */ 130 static struct proc_dir_entry *stats_root = NULL; 131 132 struct bnet_priv_t { 133 sal_sem_t tx_sem; 134 volatile int tx_thread_running; 135 struct sk_buff_head tx_queue; 136 bnet_dev_t *bdev; 137 }; 138 139 extern ibde_t *bde; 140 141 LIST_HEAD(_free_list); 142 143 static void 144 bnet_init_packets(void) 145 { 146 int i; 147 148 spin_lock_init(&packet_lock); 149 150 if (tx_buffers < 0 || tx_buffers > 4096) { 151 tx_buffers = 32; 152 } 153 154 for (i = 0; i < tx_buffers; i++) { 155 pkt_info_t *pkt = (pkt_info_t*)kmalloc(sizeof(*pkt), GFP_KERNEL); 156 memset(pkt, 0, sizeof(*pkt)); 157 pkt->pkt = (unsigned char*) bde->salloc(0, 1600, ""); 158 list_add(&pkt->list, &_free_list); 159 } 160 } 161 162 static pkt_info_t * 163 bnet_alloc_packet(void) 164 { 165 pkt_info_t *rc = NULL; 166 unsigned long flags; 167 168 spin_lock_irqsave(&packet_lock, flags); 169 if (!list_empty(&_free_list)) { 170 rc = list_entry(_free_list.next, pkt_info_t, list); 171 list_del(&rc->list); 172 rc->count++; 173 } 174 spin_unlock_irqrestore(&packet_lock, flags); 175 return rc; 176 } 177 178 static void 179 bnet_free_packet(pkt_info_t *pkt) 180 { 181 unsigned long flags; 182 183 spin_lock_irqsave(&packet_lock, flags); 184 list_add(&pkt->list, &_free_list); 185 spin_unlock_irqrestore(&packet_lock, flags); 186 } 187 188 static void 189 bnet_cleanup_packets(void) 190 { 191 while(!list_empty(&_free_list)) { 192 pkt_info_t *p; 193 p = list_entry(_free_list.next, pkt_info_t, list); 194 list_del(&p->list); 195 bde->sfree(0, p->pkt); 196 kfree(p); 197 } 198 } 199 200 /* 201 * Network Interface 202 */ 203 static void bnet_init_bdev_pbmp(bnet_dev_t *bdev) 204 { 205 int i; 206 pbmp_t pbmp_all; 207 208 BCM_PBMP_ASSIGN(pbmp_all, PBMP_PORT_ALL(unit)); 209 BCM_PBMP_CLEAR(bdev->pbmp); 210 for (i = 0; i < 8*sizeof(bdev->pmask); i++) { 211 if (((1 << i) & bdev->pmask) && BCM_PBMP_MEMBER(pbmp_all, i)) { 212 BCM_PBMP_PORT_ADD(bdev->pbmp, i); 213 } 214 } 215 } 216 217 static bnet_dev_t *bnet_bdev_from_port(int port) 218 { 219 int i; 220 221 for (i = 0; bnet_dev[i].ndev; i++) { 222 if ((1 << port) & bnet_dev[i].pmask) { 223 return &bnet_dev[i]; 224 } 225 } 226 227 return NULL; 228 } 229 230 static bnet_dev_t *bnet_bdev_from_ndev(struct net_device *dev) 231 { 232 return ((struct bnet_priv_t *)netdev_priv(dev))->bdev; 233 } 234 235 static int 236 bnet_open(struct net_device *dev) 237 { 238 netif_start_queue(dev); 239 return 0; 240 } 241 242 static int 243 bnet_stop(struct net_device *dev) 244 { 245 netif_stop_queue(dev); 246 return 0; 247 } 248 249 /* 250 * Network Device Statistics. 251 * Cleared at init time. 252 */ 253 static struct net_device_stats * 254 bnet_get_stats(struct net_device *dev) 255 { 256 bnet_dev_t *bdev = bnet_bdev_from_ndev(dev); 257 258 if (bdev == NULL) { 259 /* Unknown device */ 260 return NULL; 261 } 262 263 return &bdev->stats; 264 } 265 266 /* fake multicast ability */ 267 static void 268 bnet_set_multicast_list(struct net_device *dev) 269 { 270 } 271 272 /* bcmx_pkt_cb_f: cookie param must be ignored (rx only) */ 273 static void 274 bnet_tx_done(int ignored, bcm_pkt_t *packet, void *cookie) 275 { 276 bnet_free_packet((pkt_info_t*)packet->cookie); 277 } 278 279 static int 280 bnet_tx_deferred(struct sk_buff *skb, struct net_device *dev) 281 { 282 pkt_info_t *tx; 283 bcm_l2_addr_t l2addr; 284 pbmp_t pbmp; 285 int rv; 286 bnet_dev_t *bdev = bnet_bdev_from_ndev(dev); 287 288 if (bdev == NULL) { 289 /* Unknown device */ 290 return -1; 291 } 292 293 bdev->stats.tx_packets++; 294 bdev->stats.tx_bytes += skb->len+4; 295 tx = bnet_alloc_packet(); 296 297 if (tx) { 298 bcm_pkt_t *pkt = &tx->bcm_pkt; 299 300 memcpy(tx->pkt, skb->data, 12); 301 tx->pkt[12] = 0x81; 302 tx->pkt[13] = 0x00; 303 tx->pkt[14] = (vlan >> 8) & 0xF; 304 tx->pkt[15] = vlan & 0xFF; 305 memcpy(tx->pkt+16, skb->data+12, skb->len-12); 306 307 /* Set up bcm packet */ 308 pkt->pkt_data = &pkt->_pkt_data; 309 pkt->blk_count = 1; 310 pkt->_pkt_data.data = (uint8 *)tx->pkt; 311 pkt->_pkt_data.len = skb->len + 4; 312 pkt->flags = BCM_TX_CRC_APPEND; 313 pkt->call_back = bnet_tx_done; 314 pkt->cookie = (void *)tx; 315 316 rv = BCM_E_NOT_FOUND; 317 if (!in_interrupt() && (tx->pkt[0] & 0x1) == 0) { 318 bcm_l2_addr_t_init(&l2addr, tx->pkt, vlan); 319 rv = bcm_l2_addr_get(unit, tx->pkt, vlan, &l2addr); 320 } 321 if (rv == BCM_E_NOT_FOUND) { 322 BCM_PBMP_ASSIGN(pbmp, bdev->pbmp); 323 } else { 324 BCM_PBMP_PORT_SET(pbmp, l2addr.port); 325 } 326 BCM_PBMP_ASSIGN(pkt->tx_pbmp, pbmp); 327 BCM_PBMP_ASSIGN(pkt->tx_upbmp, pbmp); 328 329 if (bcm_tx(unit, &tx->bcm_pkt, NULL) < 0) { 330 bdev->stats.tx_errors++; 331 bnet_free_packet(tx); 332 } 333 } 334 else { 335 bdev->stats.tx_dropped++; 336 } 337 338 kfree_skb(skb); 339 return 0; 340 } 341 342 /* 343 * Currently we cannot send packets from interrupt context because 344 * bcm_l2_addr_get will try to sleep while doing S-Channel messaging. 345 * To avoid out of order transmissions, all packets are sent through 346 * the queue, even if we are called from process context. 347 */ 348 static int 349 bnet_tx(struct sk_buff *skb, struct net_device *dev) 350 { 351 #ifdef BNET_TX_THREAD 352 struct bnet_priv_t *pd = (struct bnet_priv_t *)netdev_priv(bnet_dev[0].ndev); 353 354 skb_queue_tail(&pd->tx_queue, skb); 355 sal_sem_give(pd->tx_sem); 356 #else 357 bnet_tx_deferred(skb, dev); 358 #endif 359 return 0; 360 } 361 362 #ifdef BNET_TX_THREAD 363 static void 364 bnet_tx_thread(void *p) 365 { 366 struct bnet_priv_t *pd = (struct bnet_priv_t *)netdev_priv(bnet_dev[0].ndev); 367 struct sk_buff *skb; 368 369 #ifndef CONFIG_TIMESYS 370 current->rt_priority = 50; 371 current->policy = SCHED_RR; 372 #endif 373 374 while (pd->tx_thread_running) { 375 while ((skb = skb_dequeue(&pd->tx_queue)) != NULL) { 376 bnet_tx_deferred(skb, skb->dev); 377 } 378 sal_sem_take(pd->tx_sem, sal_sem_FOREVER); 379 } 380 } 381 382 static int 383 bnet_tx_init(struct net_device *dev) 384 { 385 struct bnet_priv_t *pd = (struct bnet_priv_t *)netdev_priv(bnet_dev[0].ndev); 386 387 pd->tx_sem = sal_sem_create("bnetTX", 0, 0); 388 if (!pd->tx_sem) { 389 gprintk("Error creating thread semaphore.\n"); 390 return -1; 391 } 392 skb_queue_head_init(&pd->tx_queue); 393 pd->tx_thread_running = 1; 394 sal_thread_create("bnetTX", 0x1000, 50, bnet_tx_thread, dev); 395 return 0; 396 } 397 398 static int 399 bnet_tx_cleanup(struct net_device *dev) 400 { 401 struct bnet_priv_t *pd = (struct bnet_priv_t *)netdev_priv(bnet_dev[0].ndev); 402 struct sk_buff *skb; 403 404 pd->tx_thread_running = 0; 405 sal_sem_give(pd->tx_sem); 406 sal_usleep(500000); 407 sal_sem_destroy(pd->tx_sem); 408 while ((skb = skb_dequeue(&pd->tx_queue)) != NULL) { 409 kfree_skb(skb); 410 } 411 return 0; 412 } 413 #endif 414 415 static void 416 bnet_rx_deferred(void *packet_int, int src_port, 417 int reason, int pkt_size) 418 { 419 struct sk_buff *skb; 420 unsigned char *pkt = (unsigned char*) packet_int; 421 int i; 422 int rx_vlan; 423 bnet_dev_t *bdev = bnet_bdev_from_port(src_port); 424 425 if (bdev == NULL) { 426 /* Unknown port */ 427 return; 428 } 429 430 bdev->stats.rx_packets++; 431 bdev->stats.rx_bytes += pkt_size; 432 433 if (ENET_MACADDR_MULTICAST(pkt)) { 434 bdev->stats.multicast++; 435 } 436 437 rx_vlan = ((pkt[14] & 0x0F) << 8) + pkt[15]; 438 439 if (rx_vlan == vlan && (skb = dev_alloc_skb(pkt_size + 2)) != NULL) { 440 skb->dev = bdev->ndev; 441 skb_reserve(skb, 2); /* 16 byte align the IP fields. */ 442 443 /* Drop the VLAN tag */ 444 for (i = 11; i >= 0; i--) { 445 pkt[i+4] = pkt[i]; 446 } 447 #if ( LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)) 448 skb_copy_to_linear_data(skb, pkt+4, pkt_size-4); 449 #else 450 eth_copy_and_sum(skb, pkt+4, pkt_size-4, 0); 451 #endif 452 skb_put(skb, pkt_size); 453 454 skb->protocol = eth_type_trans(skb, skb->dev); 455 netif_rx (skb); 456 } 457 else { 458 bdev->stats.rx_dropped++; 459 } 460 } 461 462 static bcm_rx_t 463 bnet_rx(int ignored, bcm_pkt_t *pkt, void *cookie) 464 { 465 COMPILER_REFERENCE(ignored); 466 467 bnet_rx_deferred(pkt->pkt_data->data, pkt->rx_port, 0, pkt->pkt_len); 468 return BCM_RX_HANDLED; 469 } 470 471 472 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)) 473 static const struct net_device_ops bkn_netdev_ops = { 474 .ndo_open = bnet_open, 475 .ndo_stop = bnet_stop, 476 .ndo_start_xmit = bnet_tx, 477 .ndo_get_stats = bnet_get_stats, 478 .ndo_validate_addr = eth_validate_addr, 479 .ndo_set_rx_mode = bnet_set_multicast_list, 480 .ndo_set_mac_address = NULL, 481 .ndo_do_ioctl = NULL, 482 .ndo_tx_timeout = NULL, 483 .ndo_change_mtu = NULL, 484 }; 485 #endif 486 487 static struct net_device * 488 bnet_init(sal_mac_addr_t mac, bnet_dev_t *bnet_dev) 489 { 490 struct net_device *dev; 491 bcm_l2_addr_t l2addr; 492 493 /* 494 * Create the kernel ethernet device. 495 */ 496 dev = alloc_etherdev(sizeof(struct bnet_priv_t)); 497 #ifdef SET_MODULE_OWNER 498 SET_MODULE_OWNER(dev); 499 #endif 500 501 if (dev == NULL) { 502 gprintk("Error initializing ethernet device.\n"); 503 return NULL; 504 } 505 506 ((struct bnet_priv_t *)netdev_priv(dev))->bdev = bnet_dev; 507 508 /* Set the device MAC address */ 509 memcpy(dev->dev_addr, mac, 6); 510 511 /* Device information -- not available right now */ 512 dev->irq = 0; 513 dev->base_addr = 0; 514 515 /* Device vectors */ 516 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)) 517 dev->netdev_ops = &bkn_netdev_ops; 518 #else 519 dev->open = bnet_open; 520 dev->hard_start_xmit = bnet_tx; 521 dev->stop = bnet_stop; 522 dev->set_multicast_list = bnet_set_multicast_list; 523 dev->do_ioctl = NULL; 524 dev->get_stats = bnet_get_stats; 525 #endif 526 527 /* Register the kernel ethernet device */ 528 if (register_netdev(dev)) { 529 gprintk("Error registering ethernet device.\n"); 530 _free_netdev(dev); 531 return NULL; 532 } 533 534 /* Add ARL entry */ 535 bcm_l2_addr_t_init(&l2addr, mac, vlan); 536 l2addr.flags = BCM_L2_STATIC; 537 l2addr.port = CMIC_PORT(unit); 538 bcm_l2_addr_add(unit, &l2addr); 539 540 return dev; 541 } 542 543 static int 544 bnet_destroy(struct net_device *dev) 545 { 546 /* Delete ARL entry */ 547 bcm_l2_addr_delete(unit, dev->dev_addr, vlan); 548 549 unregister_netdev(dev); 550 _free_netdev(dev); 551 552 return 0; 553 } 554 555 #define STAT(p, s) { \ 556 int _rv; \ 557 uint64 _v; \ 558 _rv = bcm_stat_get(unit, (p), (s), &_v); \ 559 if (_rv >= 0) { \ 560 seq_printf(m, "%s=%d\n", #s, COMPILER_64_LO(_v)); \ 561 } \ 562 } 563 564 /* 565 * Port Statistics Proc Entries 566 */ 567 static int 568 bnet_proc_stat_show(struct seq_file *m, void *v) 569 { 570 bcm_port_t port = (bcm_port_t)PTR_TO_INT(m->private); 571 572 /*** RFC 1213 ***/ 573 574 STAT(port, snmpIfInOctets); 575 STAT(port, snmpIfInUcastPkts); 576 STAT(port, snmpIfInNUcastPkts); 577 STAT(port, snmpIfInDiscards); 578 STAT(port, snmpIfInErrors); 579 STAT(port, snmpIfInUnknownProtos); 580 STAT(port, snmpIfOutOctets); 581 STAT(port, snmpIfOutUcastPkts); 582 STAT(port, snmpIfOutNUcastPkts); 583 STAT(port, snmpIfOutDiscards); 584 STAT(port, snmpIfOutErrors); 585 STAT(port, snmpIpForwDatagrams); 586 STAT(port, snmpIpInReceives); 587 STAT(port, snmpIpInDiscards); 588 589 /*** RFC 1493 ***/ 590 591 STAT(port, snmpDot1dBasePortDelayExceededDiscards); 592 STAT(port, snmpDot1dBasePortMtuExceededDiscards); 593 STAT(port, snmpDot1dTpPortInFrames); 594 STAT(port, snmpDot1dTpPortOutFrames); 595 STAT(port, snmpDot1dPortInDiscards); 596 597 /*** RFC 1757 (EtherStat) ***/ 598 599 STAT(port, snmpEtherStatsDropEvents); 600 STAT(port, snmpEtherStatsMulticastPkts); 601 STAT(port, snmpEtherStatsBroadcastPkts); 602 STAT(port, snmpEtherStatsUndersizePkts); 603 STAT(port, snmpEtherStatsFragments); 604 STAT(port, snmpEtherStatsPkts64Octets); 605 STAT(port, snmpEtherStatsPkts65to127Octets); 606 STAT(port, snmpEtherStatsPkts128to255Octets); 607 STAT(port, snmpEtherStatsPkts256to511Octets); 608 STAT(port, snmpEtherStatsPkts512to1023Octets); 609 STAT(port, snmpEtherStatsPkts1024to1518Octets); 610 STAT(port, snmpEtherStatsOversizePkts); 611 STAT(port, snmpEtherStatsJabbers); 612 STAT(port, snmpEtherStatsOctets); 613 STAT(port, snmpEtherStatsPkts); 614 STAT(port, snmpEtherStatsCollisions); 615 STAT(port, snmpEtherStatsCRCAlignErrors); 616 STAT(port, snmpEtherStatsTXNoErrors); 617 STAT(port, snmpEtherStatsRXNoErrors); 618 619 /*** RFC 2665 ***/ 620 621 STAT(port, snmpDot3StatsAlignmentErrors); 622 STAT(port, snmpDot3StatsFCSErrors); 623 STAT(port, snmpDot3StatsSingleCollisionFrames); 624 STAT(port, snmpDot3StatsMultipleCollisionFrames); 625 STAT(port, snmpDot3StatsSQETTestErrors); 626 STAT(port, snmpDot3StatsDeferredTransmissions); 627 STAT(port, snmpDot3StatsLateCollisions); 628 STAT(port, snmpDot3StatsExcessiveCollisions); 629 STAT(port, snmpDot3StatsInternalMacTransmitErrors); 630 STAT(port, snmpDot3StatsCarrierSenseErrors); 631 STAT(port, snmpDot3StatsFrameTooLongs); 632 STAT(port, snmpDot3StatsInternalMacReceiveErrors); 633 STAT(port, snmpDot3StatsSymbolErrors); 634 635 /*** RFC 2233 ***/ 636 637 STAT(port, snmpIfHCInOctets); 638 STAT(port, snmpIfHCInUcastPkts); 639 STAT(port, snmpIfHCInMulticastPkts); 640 STAT(port, snmpIfHCInBroadcastPkts); 641 STAT(port, snmpIfHCOutOctets); 642 STAT(port, snmpIfHCOutUcastPkts); 643 STAT(port, snmpIfHCOutMulticastPkts); 644 STAT(port, snmpIfHCOutBroadcastPckts); 645 646 /*** Additional Broadcom stats ***/ 647 648 STAT(port, snmpBcmIPMCBridgedPckts); 649 STAT(port, snmpBcmIPMCRoutedPckts); 650 STAT(port, snmpBcmIPMCInDroppedPckts); 651 STAT(port, snmpBcmIPMCOutDroppedPckts); 652 653 return 0; 654 } 655 656 static int bnet_proc_stat_open(struct inode * inode, struct file * file) { 657 return single_open(file, bnet_proc_stat_show, PROC_PDE_DATA(inode)); 658 659 } 660 struct file_operations bnet_proc_stat_fops = { 661 owner: THIS_MODULE, 662 open: bnet_proc_stat_open, 663 read: seq_read, 664 llseek: seq_lseek, 665 release: single_release, 666 }; 667 668 static int 669 bnet_proc_init(void) 670 { 671 char scratch[64]; 672 pbmp_t pbm; 673 bcm_port_t port; 674 struct proc_dir_entry* entry; 675 676 stats_root = proc_mkdir("stats", bnet_proc_root); 677 678 BCM_PBMP_ASSIGN(pbm, PBMP_PORT_ALL(unit)); 679 PBMP_ITER(pbm, port) { 680 sprintf(scratch, "port%d", port); 681 PROC_CREATE_DATA(entry, scratch, 0, stats_root, &bnet_proc_stat_fops, 682 INT_TO_PTR(port)); 683 if (entry == NULL) { 684 return -1; 685 } 686 } 687 688 return 0; 689 } 690 691 static int 692 bnet_proc_cleanup(void) 693 { 694 char scratch[64]; 695 pbmp_t pbm; 696 bcm_port_t port; 697 698 BCM_PBMP_ASSIGN(pbm, PBMP_PORT_ALL(unit)); 699 PBMP_ITER(pbm, port) { 700 sprintf(scratch, "port%d", port); 701 remove_proc_entry(scratch, stats_root); 702 } 703 704 remove_proc_entry("stats", bnet_proc_root); 705 return 0; 706 } 707 708 /* 709 * Generic module functions 710 */ 711 712 static int 713 _pprint(void) 714 { 715 struct list_head *list; 716 int i=0; 717 718 pprintf("Broadcom BCM Core Linux Network Driver\n"); 719 pprintf("SOC Unit: %d\n", unit); 720 pprintf("VLAN ID: %d\n", vlan); 721 pprintf("Packet Buffer Usage Statistics (%d buffers):\n", tx_buffers); 722 list_for_each(list, &_free_list) { 723 pkt_info_t *pkt = (pkt_info_t*)list; 724 pprintf("%3d: %.8d\n", i++, pkt->count); 725 } 726 727 /* put some goodies here */ 728 return 0; 729 } 730 731 static int 732 _init(void) 733 { 734 char scratch[64]; 735 int i; 736 struct net_device *dev; 737 738 if (!soc_attached(unit)) { 739 gprintk("Error: SOC device not attached.\n"); 740 return -1; 741 } 742 743 /* Initialize ether device processing */ 744 bnet_init_packets(); 745 746 /* Randomize Lower 3 bytes of the MAC address (TESTING ONLY) */ 747 get_random_bytes(&bnet_dev_mac[3], 3); 748 749 /* Check for user-supplied MAC address (recommended) */ 750 if (mac_addr != NULL && strlen(mac_addr) == 17) { 751 for (i = 0; i < 6; i++) { 752 bnet_dev_mac[i] = simple_strtoul(&mac_addr[i*3], NULL, 16) & 0xFF; 753 } 754 /* Do not allow multicast address */ 755 bnet_dev_mac[0] &= ~0x01; 756 } 757 758 /* Initialize BCM driver */ 759 system_init(unit); 760 761 bnet_init_bdev_pbmp(&bnet_dev[0]); 762 if ((dev = bnet_init(bnet_dev_mac, &bnet_dev[0])) == NULL) { 763 return -1; 764 } 765 bnet_dev[0].ndev = dev; 766 767 /* Create virtual devices as needed */ 768 for (i = 1; bnet_dev[i].pmask; i++) { 769 bnet_dev_mac[5]++; 770 bnet_init_bdev_pbmp(&bnet_dev[i]); 771 if ((dev = bnet_init(bnet_dev_mac, &bnet_dev[i])) == NULL) { 772 return -1; 773 } 774 bnet_dev[i].ndev = dev; 775 } 776 777 bcm_rx_register(unit, "bcm-net", bnet_rx, BCM_RX_PRIO_MAX, NULL, 778 BCM_RCO_F_ALL_COS | BCM_RCO_F_INTR); 779 bcm_rx_start(unit, NULL); 780 781 /* Initialize TX */ 782 #ifdef BNET_TX_THREAD 783 bnet_tx_init(bnet_dev[0].ndev); 784 #endif 785 786 /* Initialize proc files */ 787 proc_mkdir("bcm", NULL); 788 sprintf(scratch, "bcm/%s", bnet_dev[0].ndev->name); 789 bnet_proc_root = proc_mkdir(scratch, NULL); 790 791 bnet_proc_init(); 792 return 0; 793 } 794 795 static int 796 _cleanup(void) 797 { 798 char scratch[64]; 799 int i; 800 801 bcm_rx_stop(unit, NULL); 802 bcm_rx_unregister(unit, bnet_rx, BCM_RX_PRIO_MAX); 803 bnet_cleanup_packets(); 804 #ifdef BNET_TX_THREAD 805 bnet_tx_cleanup(bnet_dev[0].ndev); 806 #endif 807 808 bnet_proc_cleanup(); 809 sprintf(scratch, "bcm/%s", bnet_dev[0].ndev->name); 810 remove_proc_entry(scratch, NULL); 811 remove_proc_entry("bcm", NULL); 812 813 for (i = 0; bnet_dev[i].ndev; i++) { 814 bnet_destroy(bnet_dev[i].ndev); 815 } 816 817 return 0; 818 } 819 820 static gmodule_t _gmodule = { 821 name: MODULE_NAME, 822 major: MODULE_MAJOR, 823 init: _init, 824 cleanup: _cleanup, 825 pprint: _pprint, 826 ioctl: NULL, 827 open: NULL, 828 close: NULL, 829 }; 830 831 gmodule_t* 832 gmodule_get(void) 833 { 834 EXPORT_NO_SYMBOLS; 835 return &_gmodule; 836 }