aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/misc/sgi-xp/xpnet.c
diff options
context:
space:
mode:
authorDean Nelson <dcn@sgi.com>2008-07-30 01:34:12 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-07-30 12:41:50 -0400
commita7b4d509205db5e9cd3ffc77b306d7b10fe6a34d (patch)
tree2983c8835c5aa391f540196bb610e0394ef5d56d /drivers/misc/sgi-xp/xpnet.c
parent185c3a1b4bb4353529257f97caaeaac6c695e77d (diff)
sgi-xp: enable XPNET to handle more than 64 partitions
Enable XPNET to support more than 64 partitions. Signed-off-by: Dean Nelson <dcn@sgi.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/misc/sgi-xp/xpnet.c')
-rw-r--r--drivers/misc/sgi-xp/xpnet.c213
1 files changed, 94 insertions, 119 deletions
diff --git a/drivers/misc/sgi-xp/xpnet.c b/drivers/misc/sgi-xp/xpnet.c
index f9356ba73155..c5f59a6dae52 100644
--- a/drivers/misc/sgi-xp/xpnet.c
+++ b/drivers/misc/sgi-xp/xpnet.c
@@ -21,7 +21,6 @@
21 */ 21 */
22 22
23#include <linux/module.h> 23#include <linux/module.h>
24#include <linux/types.h>
25#include <linux/kernel.h> 24#include <linux/kernel.h>
26#include <linux/init.h> 25#include <linux/init.h>
27#include <linux/ioport.h> 26#include <linux/ioport.h>
@@ -32,8 +31,6 @@
32#include <linux/mii.h> 31#include <linux/mii.h>
33#include <linux/smp.h> 32#include <linux/smp.h>
34#include <linux/string.h> 33#include <linux/string.h>
35#include <asm/sn/io.h>
36#include <asm/sn/sn_sal.h>
37#include <asm/atomic.h> 34#include <asm/atomic.h>
38#include "xp.h" 35#include "xp.h"
39 36
@@ -104,7 +101,6 @@ struct xpnet_message {
104 * then be released. 101 * then be released.
105 */ 102 */
106struct xpnet_pending_msg { 103struct xpnet_pending_msg {
107 struct list_head free_list;
108 struct sk_buff *skb; 104 struct sk_buff *skb;
109 atomic_t use_count; 105 atomic_t use_count;
110}; 106};
@@ -120,7 +116,7 @@ struct net_device *xpnet_device;
120 * When we are notified of other partitions activating, we add them to 116 * When we are notified of other partitions activating, we add them to
121 * our bitmask of partitions to which we broadcast. 117 * our bitmask of partitions to which we broadcast.
122 */ 118 */
123static u64 xpnet_broadcast_partitions; 119static unsigned long *xpnet_broadcast_partitions;
124/* protect above */ 120/* protect above */
125static DEFINE_SPINLOCK(xpnet_broadcast_lock); 121static DEFINE_SPINLOCK(xpnet_broadcast_lock);
126 122
@@ -140,16 +136,13 @@ static DEFINE_SPINLOCK(xpnet_broadcast_lock);
140#define XPNET_DEF_MTU (0x8000UL) 136#define XPNET_DEF_MTU (0x8000UL)
141 137
142/* 138/*
143 * The partition id is encapsulated in the MAC address. The following 139 * The partid is encapsulated in the MAC address beginning in the following
144 * define locates the octet the partid is in. 140 * octet and it consists of two octets.
145 */ 141 */
146#define XPNET_PARTID_OCTET 1 142#define XPNET_PARTID_OCTET 2
147#define XPNET_LICENSE_OCTET 2 143
144/* Define the XPNET debug device structures to be used with dev_dbg() et al */
148 145
149/*
150 * Define the XPNET debug device structure that is to be used with dev_dbg(),
151 * dev_err(), dev_warn(), and dev_info().
152 */
153struct device_driver xpnet_dbg_name = { 146struct device_driver xpnet_dbg_name = {
154 .name = "xpnet" 147 .name = "xpnet"
155}; 148};
@@ -231,7 +224,7 @@ xpnet_receive(short partid, int channel, struct xpnet_message *msg)
231 (void *)msg->buf_pa, msg->size); 224 (void *)msg->buf_pa, msg->size);
232 225
233 ret = xp_remote_memcpy((void *)((u64)skb->data & 226 ret = xp_remote_memcpy((void *)((u64)skb->data &
234 ~(L1_CACHE_BYTES - 1)), 227 ~(L1_CACHE_BYTES - 1)),
235 (void *)msg->buf_pa, msg->size); 228 (void *)msg->buf_pa, msg->size);
236 229
237 if (ret != xpSuccess) { 230 if (ret != xpSuccess) {
@@ -283,8 +276,6 @@ static void
283xpnet_connection_activity(enum xp_retval reason, short partid, int channel, 276xpnet_connection_activity(enum xp_retval reason, short partid, int channel,
284 void *data, void *key) 277 void *data, void *key)
285{ 278{
286 long bp;
287
288 DBUG_ON(partid < 0 || partid >= xp_max_npartitions); 279 DBUG_ON(partid < 0 || partid >= xp_max_npartitions);
289 DBUG_ON(channel != XPC_NET_CHANNEL); 280 DBUG_ON(channel != XPC_NET_CHANNEL);
290 281
@@ -297,31 +288,28 @@ xpnet_connection_activity(enum xp_retval reason, short partid, int channel,
297 288
298 case xpConnected: /* connection completed to a partition */ 289 case xpConnected: /* connection completed to a partition */
299 spin_lock_bh(&xpnet_broadcast_lock); 290 spin_lock_bh(&xpnet_broadcast_lock);
300 xpnet_broadcast_partitions |= 1UL << (partid - 1); 291 __set_bit(partid, xpnet_broadcast_partitions);
301 bp = xpnet_broadcast_partitions;
302 spin_unlock_bh(&xpnet_broadcast_lock); 292 spin_unlock_bh(&xpnet_broadcast_lock);
303 293
304 netif_carrier_on(xpnet_device); 294 netif_carrier_on(xpnet_device);
305 295
306 dev_dbg(xpnet, "%s connection created to partition %d; " 296 dev_dbg(xpnet, "%s connected to partition %d\n",
307 "xpnet_broadcast_partitions=0x%lx\n", 297 xpnet_device->name, partid);
308 xpnet_device->name, partid, bp);
309 break; 298 break;
310 299
311 default: 300 default:
312 spin_lock_bh(&xpnet_broadcast_lock); 301 spin_lock_bh(&xpnet_broadcast_lock);
313 xpnet_broadcast_partitions &= ~(1UL << (partid - 1)); 302 __clear_bit(partid, xpnet_broadcast_partitions);
314 bp = xpnet_broadcast_partitions;
315 spin_unlock_bh(&xpnet_broadcast_lock); 303 spin_unlock_bh(&xpnet_broadcast_lock);
316 304
317 if (bp == 0) 305 if (bitmap_empty((unsigned long *)xpnet_broadcast_partitions,
306 xp_max_npartitions)) {
318 netif_carrier_off(xpnet_device); 307 netif_carrier_off(xpnet_device);
308 }
319 309
320 dev_dbg(xpnet, "%s disconnected from partition %d; " 310 dev_dbg(xpnet, "%s disconnected from partition %d\n",
321 "xpnet_broadcast_partitions=0x%lx\n", 311 xpnet_device->name, partid);
322 xpnet_device->name, partid, bp);
323 break; 312 break;
324
325 } 313 }
326} 314}
327 315
@@ -424,36 +412,72 @@ xpnet_send_completed(enum xp_retval reason, short partid, int channel,
424 } 412 }
425} 413}
426 414
415static void
416xpnet_send(struct sk_buff *skb, struct xpnet_pending_msg *queued_msg,
417 u64 start_addr, u64 end_addr, u16 embedded_bytes, int dest_partid)
418{
419 u8 msg_buffer[XPNET_MSG_SIZE];
420 struct xpnet_message *msg = (struct xpnet_message *)&msg_buffer;
421 enum xp_retval ret;
422
423 msg->embedded_bytes = embedded_bytes;
424 if (unlikely(embedded_bytes != 0)) {
425 msg->version = XPNET_VERSION_EMBED;
426 dev_dbg(xpnet, "calling memcpy(0x%p, 0x%p, 0x%lx)\n",
427 &msg->data, skb->data, (size_t)embedded_bytes);
428 skb_copy_from_linear_data(skb, &msg->data,
429 (size_t)embedded_bytes);
430 } else {
431 msg->version = XPNET_VERSION;
432 }
433 msg->magic = XPNET_MAGIC;
434 msg->size = end_addr - start_addr;
435 msg->leadin_ignore = (u64)skb->data - start_addr;
436 msg->tailout_ignore = end_addr - (u64)skb_tail_pointer(skb);
437 msg->buf_pa = __pa(start_addr);
438
439 dev_dbg(xpnet, "sending XPC message to %d:%d\n"
440 KERN_DEBUG "msg->buf_pa=0x%lx, msg->size=%u, "
441 "msg->leadin_ignore=%u, msg->tailout_ignore=%u\n",
442 dest_partid, XPC_NET_CHANNEL, msg->buf_pa, msg->size,
443 msg->leadin_ignore, msg->tailout_ignore);
444
445 atomic_inc(&queued_msg->use_count);
446
447 ret = xpc_send_notify(dest_partid, XPC_NET_CHANNEL, XPC_NOWAIT, msg,
448 XPNET_MSG_SIZE, xpnet_send_completed, queued_msg);
449 if (unlikely(ret != xpSuccess))
450 atomic_dec(&queued_msg->use_count);
451}
452
427/* 453/*
428 * Network layer has formatted a packet (skb) and is ready to place it 454 * Network layer has formatted a packet (skb) and is ready to place it
429 * "on the wire". Prepare and send an xpnet_message to all partitions 455 * "on the wire". Prepare and send an xpnet_message to all partitions
430 * which have connected with us and are targets of this packet. 456 * which have connected with us and are targets of this packet.
431 * 457 *
432 * MAC-NOTE: For the XPNET driver, the MAC address contains the 458 * MAC-NOTE: For the XPNET driver, the MAC address contains the
433 * destination partition_id. If the destination partition id word 459 * destination partid. If the destination partid octets are 0xffff,
434 * is 0xff, this packet is to broadcast to all partitions. 460 * this packet is to be broadcast to all connected partitions.
435 */ 461 */
436static int 462static int
437xpnet_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) 463xpnet_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
438{ 464{
439 struct xpnet_pending_msg *queued_msg; 465 struct xpnet_pending_msg *queued_msg;
440 enum xp_retval ret;
441 u8 msg_buffer[XPNET_MSG_SIZE];
442 struct xpnet_message *msg = (struct xpnet_message *)&msg_buffer[0];
443 u64 start_addr, end_addr; 466 u64 start_addr, end_addr;
444 long dp;
445 u8 second_mac_octet;
446 short dest_partid; 467 short dest_partid;
447 struct xpnet_dev_private *priv; 468 struct xpnet_dev_private *priv = (struct xpnet_dev_private *)dev->priv;
448 u16 embedded_bytes; 469 u16 embedded_bytes = 0;
449
450 priv = (struct xpnet_dev_private *)dev->priv;
451 470
452 dev_dbg(xpnet, ">skb->head=0x%p skb->data=0x%p skb->tail=0x%p " 471 dev_dbg(xpnet, ">skb->head=0x%p skb->data=0x%p skb->tail=0x%p "
453 "skb->end=0x%p skb->len=%d\n", (void *)skb->head, 472 "skb->end=0x%p skb->len=%d\n", (void *)skb->head,
454 (void *)skb->data, skb_tail_pointer(skb), skb_end_pointer(skb), 473 (void *)skb->data, skb_tail_pointer(skb), skb_end_pointer(skb),
455 skb->len); 474 skb->len);
456 475
476 if (skb->data[0] == 0x33) {
477 dev_kfree_skb(skb);
478 return 0; /* nothing needed to be done */
479 }
480
457 /* 481 /*
458 * The xpnet_pending_msg tracks how many outstanding 482 * The xpnet_pending_msg tracks how many outstanding
459 * xpc_send_notifies are relying on this skb. When none 483 * xpc_send_notifies are relying on this skb. When none
@@ -465,7 +489,6 @@ xpnet_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
465 "packet\n", sizeof(struct xpnet_pending_msg)); 489 "packet\n", sizeof(struct xpnet_pending_msg));
466 490
467 priv->stats.tx_errors++; 491 priv->stats.tx_errors++;
468
469 return -ENOMEM; 492 return -ENOMEM;
470 } 493 }
471 494
@@ -474,7 +497,6 @@ xpnet_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
474 end_addr = L1_CACHE_ALIGN((u64)skb_tail_pointer(skb)); 497 end_addr = L1_CACHE_ALIGN((u64)skb_tail_pointer(skb));
475 498
476 /* calculate how many bytes to embed in the XPC message */ 499 /* calculate how many bytes to embed in the XPC message */
477 embedded_bytes = 0;
478 if (unlikely(skb->len <= XPNET_MSG_DATA_MAX)) { 500 if (unlikely(skb->len <= XPNET_MSG_DATA_MAX)) {
479 /* skb->data does fit so embed */ 501 /* skb->data does fit so embed */
480 embedded_bytes = skb->len; 502 embedded_bytes = skb->len;
@@ -490,78 +512,28 @@ xpnet_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
490 atomic_set(&queued_msg->use_count, 1); 512 atomic_set(&queued_msg->use_count, 1);
491 queued_msg->skb = skb; 513 queued_msg->skb = skb;
492 514
493 second_mac_octet = skb->data[XPNET_PARTID_OCTET]; 515 if (skb->data[0] == 0xff) {
494 if (second_mac_octet == 0xff) {
495 /* we are being asked to broadcast to all partitions */ 516 /* we are being asked to broadcast to all partitions */
496 dp = xpnet_broadcast_partitions; 517 for_each_bit(dest_partid, xpnet_broadcast_partitions,
497 } else if (second_mac_octet != 0) { 518 xp_max_npartitions) {
498 dp = xpnet_broadcast_partitions &
499 (1UL << (second_mac_octet - 1));
500 } else {
501 /* 0 is an invalid partid. Ignore */
502 dp = 0;
503 }
504 dev_dbg(xpnet, "destination Partitions mask (dp) = 0x%lx\n", dp);
505
506 /*
507 * If we wanted to allow promiscuous mode to work like an
508 * unswitched network, this would be a good point to OR in a
509 * mask of partitions which should be receiving all packets.
510 */
511
512 /*
513 * Main send loop.
514 */
515 for (dest_partid = 0; dp && dest_partid < xp_max_npartitions;
516 dest_partid++) {
517 519
518 if (!(dp & (1UL << (dest_partid - 1)))) { 520 xpnet_send(skb, queued_msg, start_addr, end_addr,
519 /* not destined for this partition */ 521 embedded_bytes, dest_partid);
520 continue;
521 } 522 }
523 } else {
524 dest_partid = (short)skb->data[XPNET_PARTID_OCTET + 1];
525 dest_partid |= (short)skb->data[XPNET_PARTID_OCTET + 0] << 8;
522 526
523 /* remove this partition from the destinations mask */ 527 if (dest_partid >= 0 &&
524 dp &= ~(1UL << (dest_partid - 1)); 528 dest_partid < xp_max_npartitions &&
525 529 test_bit(dest_partid, xpnet_broadcast_partitions) != 0) {
526 /* found a partition to send to */
527 530
528 msg->embedded_bytes = embedded_bytes; 531 xpnet_send(skb, queued_msg, start_addr, end_addr,
529 if (unlikely(embedded_bytes != 0)) { 532 embedded_bytes, dest_partid);
530 msg->version = XPNET_VERSION_EMBED;
531 dev_dbg(xpnet, "calling memcpy(0x%p, 0x%p, 0x%lx)\n",
532 &msg->data, skb->data, (size_t)embedded_bytes);
533 skb_copy_from_linear_data(skb, &msg->data,
534 (size_t)embedded_bytes);
535 } else {
536 msg->version = XPNET_VERSION;
537 }
538 msg->magic = XPNET_MAGIC;
539 msg->size = end_addr - start_addr;
540 msg->leadin_ignore = (u64)skb->data - start_addr;
541 msg->tailout_ignore = end_addr - (u64)skb_tail_pointer(skb);
542 msg->buf_pa = __pa(start_addr);
543
544 dev_dbg(xpnet, "sending XPC message to %d:%d\n"
545 KERN_DEBUG "msg->buf_pa=0x%lx, msg->size=%u, "
546 "msg->leadin_ignore=%u, msg->tailout_ignore=%u\n",
547 dest_partid, XPC_NET_CHANNEL, msg->buf_pa, msg->size,
548 msg->leadin_ignore, msg->tailout_ignore);
549
550 atomic_inc(&queued_msg->use_count);
551
552 ret = xpc_send_notify(dest_partid, XPC_NET_CHANNEL, XPC_NOWAIT,
553 &msg, sizeof(msg) + embedded_bytes - 1,
554 xpnet_send_completed, queued_msg);
555 if (unlikely(ret != xpSuccess)) {
556 atomic_dec(&queued_msg->use_count);
557 continue;
558 } 533 }
559 } 534 }
560 535
561 if (atomic_dec_return(&queued_msg->use_count) == 0) { 536 if (atomic_dec_return(&queued_msg->use_count) == 0) {
562 dev_dbg(xpnet, "no partitions to receive packet destined for "
563 "%d\n", dest_partid);
564
565 dev_kfree_skb(skb); 537 dev_kfree_skb(skb);
566 kfree(queued_msg); 538 kfree(queued_msg);
567 } 539 }
@@ -589,23 +561,28 @@ xpnet_dev_tx_timeout(struct net_device *dev)
589static int __init 561static int __init
590xpnet_init(void) 562xpnet_init(void)
591{ 563{
592 int i; 564 int result;
593 u32 license_num;
594 int result = -ENOMEM;
595 565
596 if (!ia64_platform_is("sn2")) 566 if (!is_shub() && !is_uv())
597 return -ENODEV; 567 return -ENODEV;
598 568
599 dev_info(xpnet, "registering network device %s\n", XPNET_DEVICE_NAME); 569 dev_info(xpnet, "registering network device %s\n", XPNET_DEVICE_NAME);
600 570
571 xpnet_broadcast_partitions = kzalloc(BITS_TO_LONGS(xp_max_npartitions) *
572 sizeof(long), GFP_KERNEL);
573 if (xpnet_broadcast_partitions == NULL)
574 return -ENOMEM;
575
601 /* 576 /*
602 * use ether_setup() to init the majority of our device 577 * use ether_setup() to init the majority of our device
603 * structure and then override the necessary pieces. 578 * structure and then override the necessary pieces.
604 */ 579 */
605 xpnet_device = alloc_netdev(sizeof(struct xpnet_dev_private), 580 xpnet_device = alloc_netdev(sizeof(struct xpnet_dev_private),
606 XPNET_DEVICE_NAME, ether_setup); 581 XPNET_DEVICE_NAME, ether_setup);
607 if (xpnet_device == NULL) 582 if (xpnet_device == NULL) {
583 kfree(xpnet_broadcast_partitions);
608 return -ENOMEM; 584 return -ENOMEM;
585 }
609 586
610 netif_carrier_off(xpnet_device); 587 netif_carrier_off(xpnet_device);
611 588
@@ -623,14 +600,10 @@ xpnet_init(void)
623 * MAC addresses. We chose the first octet of the MAC to be unlikely 600 * MAC addresses. We chose the first octet of the MAC to be unlikely
624 * to collide with any vendor's officially issued MAC. 601 * to collide with any vendor's officially issued MAC.
625 */ 602 */
626 xpnet_device->dev_addr[0] = 0xfe; 603 xpnet_device->dev_addr[0] = 0x02; /* locally administered, no OUI */
627 xpnet_device->dev_addr[XPNET_PARTID_OCTET] = sn_partition_id; 604
628 license_num = sn_partition_serial_number_val(); 605 xpnet_device->dev_addr[XPNET_PARTID_OCTET + 1] = sn_partition_id;
629 for (i = 3; i >= 0; i--) { 606 xpnet_device->dev_addr[XPNET_PARTID_OCTET + 0] = (sn_partition_id >> 8);
630 xpnet_device->dev_addr[XPNET_LICENSE_OCTET + i] =
631 license_num & 0xff;
632 license_num = license_num >> 8;
633 }
634 607
635 /* 608 /*
636 * ether_setup() sets this to a multicast device. We are 609 * ether_setup() sets this to a multicast device. We are
@@ -646,8 +619,10 @@ xpnet_init(void)
646 xpnet_device->features = NETIF_F_NO_CSUM; 619 xpnet_device->features = NETIF_F_NO_CSUM;
647 620
648 result = register_netdev(xpnet_device); 621 result = register_netdev(xpnet_device);
649 if (result != 0) 622 if (result != 0) {
650 free_netdev(xpnet_device); 623 free_netdev(xpnet_device);
624 kfree(xpnet_broadcast_partitions);
625 }
651 626
652 return result; 627 return result;
653} 628}
@@ -661,8 +636,8 @@ xpnet_exit(void)
661 xpnet_device[0].name); 636 xpnet_device[0].name);
662 637
663 unregister_netdev(xpnet_device); 638 unregister_netdev(xpnet_device);
664
665 free_netdev(xpnet_device); 639 free_netdev(xpnet_device);
640 kfree(xpnet_broadcast_partitions);
666} 641}
667 642
668module_exit(xpnet_exit); 643module_exit(xpnet_exit);