diff options
Diffstat (limited to 'drivers/misc/sgi-xp/xpnet.c')
-rw-r--r-- | drivers/misc/sgi-xp/xpnet.c | 277 |
1 files changed, 119 insertions, 158 deletions
diff --git a/drivers/misc/sgi-xp/xpnet.c b/drivers/misc/sgi-xp/xpnet.c index 822dc8e8d7f..71513b3af70 100644 --- a/drivers/misc/sgi-xp/xpnet.c +++ b/drivers/misc/sgi-xp/xpnet.c | |||
@@ -21,21 +21,8 @@ | |||
21 | */ | 21 | */ |
22 | 22 | ||
23 | #include <linux/module.h> | 23 | #include <linux/module.h> |
24 | #include <linux/types.h> | ||
25 | #include <linux/kernel.h> | ||
26 | #include <linux/init.h> | ||
27 | #include <linux/ioport.h> | ||
28 | #include <linux/netdevice.h> | 24 | #include <linux/netdevice.h> |
29 | #include <linux/etherdevice.h> | 25 | #include <linux/etherdevice.h> |
30 | #include <linux/delay.h> | ||
31 | #include <linux/ethtool.h> | ||
32 | #include <linux/mii.h> | ||
33 | #include <linux/smp.h> | ||
34 | #include <linux/string.h> | ||
35 | #include <asm/sn/bte.h> | ||
36 | #include <asm/sn/io.h> | ||
37 | #include <asm/sn/sn_sal.h> | ||
38 | #include <asm/atomic.h> | ||
39 | #include "xp.h" | 26 | #include "xp.h" |
40 | 27 | ||
41 | /* | 28 | /* |
@@ -57,7 +44,7 @@ struct xpnet_message { | |||
57 | u16 version; /* Version for this message */ | 44 | u16 version; /* Version for this message */ |
58 | u16 embedded_bytes; /* #of bytes embedded in XPC message */ | 45 | u16 embedded_bytes; /* #of bytes embedded in XPC message */ |
59 | u32 magic; /* Special number indicating this is xpnet */ | 46 | u32 magic; /* Special number indicating this is xpnet */ |
60 | u64 buf_pa; /* phys address of buffer to retrieve */ | 47 | unsigned long buf_pa; /* phys address of buffer to retrieve */ |
61 | u32 size; /* #of bytes in buffer */ | 48 | u32 size; /* #of bytes in buffer */ |
62 | u8 leadin_ignore; /* #of bytes to ignore at the beginning */ | 49 | u8 leadin_ignore; /* #of bytes to ignore at the beginning */ |
63 | u8 tailout_ignore; /* #of bytes to ignore at the end */ | 50 | u8 tailout_ignore; /* #of bytes to ignore at the end */ |
@@ -70,11 +57,10 @@ struct xpnet_message { | |||
70 | * | 57 | * |
71 | * XPC expects each message to exist in an individual cacheline. | 58 | * XPC expects each message to exist in an individual cacheline. |
72 | */ | 59 | */ |
73 | #define XPNET_MSG_SIZE (L1_CACHE_BYTES - XPC_MSG_PAYLOAD_OFFSET) | 60 | #define XPNET_MSG_SIZE XPC_MSG_PAYLOAD_MAX_SIZE |
74 | #define XPNET_MSG_DATA_MAX \ | 61 | #define XPNET_MSG_DATA_MAX \ |
75 | (XPNET_MSG_SIZE - (u64)(&((struct xpnet_message *)0)->data)) | 62 | (XPNET_MSG_SIZE - offsetof(struct xpnet_message, data)) |
76 | #define XPNET_MSG_ALIGNED_SIZE (L1_CACHE_ALIGN(XPNET_MSG_SIZE)) | 63 | #define XPNET_MSG_NENTRIES (PAGE_SIZE / XPC_MSG_MAX_SIZE) |
77 | #define XPNET_MSG_NENTRIES (PAGE_SIZE / XPNET_MSG_ALIGNED_SIZE) | ||
78 | 64 | ||
79 | #define XPNET_MAX_KTHREADS (XPNET_MSG_NENTRIES + 1) | 65 | #define XPNET_MAX_KTHREADS (XPNET_MSG_NENTRIES + 1) |
80 | #define XPNET_MAX_IDLE_KTHREADS (XPNET_MSG_NENTRIES + 1) | 66 | #define XPNET_MAX_IDLE_KTHREADS (XPNET_MSG_NENTRIES + 1) |
@@ -105,7 +91,6 @@ struct xpnet_message { | |||
105 | * then be released. | 91 | * then be released. |
106 | */ | 92 | */ |
107 | struct xpnet_pending_msg { | 93 | struct xpnet_pending_msg { |
108 | struct list_head free_list; | ||
109 | struct sk_buff *skb; | 94 | struct sk_buff *skb; |
110 | atomic_t use_count; | 95 | atomic_t use_count; |
111 | }; | 96 | }; |
@@ -121,7 +106,7 @@ struct net_device *xpnet_device; | |||
121 | * When we are notified of other partitions activating, we add them to | 106 | * When we are notified of other partitions activating, we add them to |
122 | * our bitmask of partitions to which we broadcast. | 107 | * our bitmask of partitions to which we broadcast. |
123 | */ | 108 | */ |
124 | static u64 xpnet_broadcast_partitions; | 109 | static unsigned long *xpnet_broadcast_partitions; |
125 | /* protect above */ | 110 | /* protect above */ |
126 | static DEFINE_SPINLOCK(xpnet_broadcast_lock); | 111 | static DEFINE_SPINLOCK(xpnet_broadcast_lock); |
127 | 112 | ||
@@ -141,16 +126,13 @@ static DEFINE_SPINLOCK(xpnet_broadcast_lock); | |||
141 | #define XPNET_DEF_MTU (0x8000UL) | 126 | #define XPNET_DEF_MTU (0x8000UL) |
142 | 127 | ||
143 | /* | 128 | /* |
144 | * The partition id is encapsulated in the MAC address. The following | 129 | * The partid is encapsulated in the MAC address beginning in the following |
145 | * define locates the octet the partid is in. | 130 | * octet and it consists of two octets. |
146 | */ | 131 | */ |
147 | #define XPNET_PARTID_OCTET 1 | 132 | #define XPNET_PARTID_OCTET 2 |
148 | #define XPNET_LICENSE_OCTET 2 | 133 | |
134 | /* Define the XPNET debug device structures to be used with dev_dbg() et al */ | ||
149 | 135 | ||
150 | /* | ||
151 | * Define the XPNET debug device structure that is to be used with dev_dbg(), | ||
152 | * dev_err(), dev_warn(), and dev_info(). | ||
153 | */ | ||
154 | struct device_driver xpnet_dbg_name = { | 136 | struct device_driver xpnet_dbg_name = { |
155 | .name = "xpnet" | 137 | .name = "xpnet" |
156 | }; | 138 | }; |
@@ -169,7 +151,8 @@ static void | |||
169 | xpnet_receive(short partid, int channel, struct xpnet_message *msg) | 151 | xpnet_receive(short partid, int channel, struct xpnet_message *msg) |
170 | { | 152 | { |
171 | struct sk_buff *skb; | 153 | struct sk_buff *skb; |
172 | bte_result_t bret; | 154 | void *dst; |
155 | enum xp_retval ret; | ||
173 | struct xpnet_dev_private *priv = | 156 | struct xpnet_dev_private *priv = |
174 | (struct xpnet_dev_private *)xpnet_device->priv; | 157 | (struct xpnet_dev_private *)xpnet_device->priv; |
175 | 158 | ||
@@ -201,7 +184,7 @@ xpnet_receive(short partid, int channel, struct xpnet_message *msg) | |||
201 | 184 | ||
202 | /* | 185 | /* |
203 | * The allocated skb has some reserved space. | 186 | * The allocated skb has some reserved space. |
204 | * In order to use bte_copy, we need to get the | 187 | * In order to use xp_remote_memcpy(), we need to get the |
205 | * skb->data pointer moved forward. | 188 | * skb->data pointer moved forward. |
206 | */ | 189 | */ |
207 | skb_reserve(skb, (L1_CACHE_BYTES - ((u64)skb->data & | 190 | skb_reserve(skb, (L1_CACHE_BYTES - ((u64)skb->data & |
@@ -226,26 +209,21 @@ xpnet_receive(short partid, int channel, struct xpnet_message *msg) | |||
226 | skb_copy_to_linear_data(skb, &msg->data, | 209 | skb_copy_to_linear_data(skb, &msg->data, |
227 | (size_t)msg->embedded_bytes); | 210 | (size_t)msg->embedded_bytes); |
228 | } else { | 211 | } else { |
212 | dst = (void *)((u64)skb->data & ~(L1_CACHE_BYTES - 1)); | ||
229 | dev_dbg(xpnet, "transferring buffer to the skb->data area;\n\t" | 213 | dev_dbg(xpnet, "transferring buffer to the skb->data area;\n\t" |
230 | "bte_copy(0x%p, 0x%p, %hu)\n", (void *)msg->buf_pa, | 214 | "xp_remote_memcpy(0x%p, 0x%p, %hu)\n", dst, |
231 | (void *)__pa((u64)skb->data & ~(L1_CACHE_BYTES - 1)), | 215 | (void *)msg->buf_pa, msg->size); |
232 | msg->size); | ||
233 | |||
234 | bret = bte_copy(msg->buf_pa, | ||
235 | __pa((u64)skb->data & ~(L1_CACHE_BYTES - 1)), | ||
236 | msg->size, (BTE_NOTIFY | BTE_WACQUIRE), NULL); | ||
237 | 216 | ||
238 | if (bret != BTE_SUCCESS) { | 217 | ret = xp_remote_memcpy(xp_pa(dst), msg->buf_pa, msg->size); |
218 | if (ret != xpSuccess) { | ||
239 | /* | 219 | /* |
240 | * >>> Need better way of cleaning skb. Currently skb | 220 | * !!! Need better way of cleaning skb. Currently skb |
241 | * >>> appears in_use and we can't just call | 221 | * !!! appears in_use and we can't just call |
242 | * >>> dev_kfree_skb. | 222 | * !!! dev_kfree_skb. |
243 | */ | 223 | */ |
244 | dev_err(xpnet, "bte_copy(0x%p, 0x%p, 0x%hx) returned " | 224 | dev_err(xpnet, "xp_remote_memcpy(0x%p, 0x%p, 0x%hx) " |
245 | "error=0x%x\n", (void *)msg->buf_pa, | 225 | "returned error=0x%x\n", dst, |
246 | (void *)__pa((u64)skb->data & | 226 | (void *)msg->buf_pa, msg->size, ret); |
247 | ~(L1_CACHE_BYTES - 1)), | ||
248 | msg->size, bret); | ||
249 | 227 | ||
250 | xpc_received(partid, channel, (void *)msg); | 228 | xpc_received(partid, channel, (void *)msg); |
251 | 229 | ||
@@ -285,9 +263,7 @@ static void | |||
285 | xpnet_connection_activity(enum xp_retval reason, short partid, int channel, | 263 | xpnet_connection_activity(enum xp_retval reason, short partid, int channel, |
286 | void *data, void *key) | 264 | void *data, void *key) |
287 | { | 265 | { |
288 | long bp; | 266 | DBUG_ON(partid < 0 || partid >= xp_max_npartitions); |
289 | |||
290 | DBUG_ON(partid <= 0 || partid >= XP_MAX_PARTITIONS); | ||
291 | DBUG_ON(channel != XPC_NET_CHANNEL); | 267 | DBUG_ON(channel != XPC_NET_CHANNEL); |
292 | 268 | ||
293 | switch (reason) { | 269 | switch (reason) { |
@@ -299,31 +275,28 @@ xpnet_connection_activity(enum xp_retval reason, short partid, int channel, | |||
299 | 275 | ||
300 | case xpConnected: /* connection completed to a partition */ | 276 | case xpConnected: /* connection completed to a partition */ |
301 | spin_lock_bh(&xpnet_broadcast_lock); | 277 | spin_lock_bh(&xpnet_broadcast_lock); |
302 | xpnet_broadcast_partitions |= 1UL << (partid - 1); | 278 | __set_bit(partid, xpnet_broadcast_partitions); |
303 | bp = xpnet_broadcast_partitions; | ||
304 | spin_unlock_bh(&xpnet_broadcast_lock); | 279 | spin_unlock_bh(&xpnet_broadcast_lock); |
305 | 280 | ||
306 | netif_carrier_on(xpnet_device); | 281 | netif_carrier_on(xpnet_device); |
307 | 282 | ||
308 | dev_dbg(xpnet, "%s connection created to partition %d; " | 283 | dev_dbg(xpnet, "%s connected to partition %d\n", |
309 | "xpnet_broadcast_partitions=0x%lx\n", | 284 | xpnet_device->name, partid); |
310 | xpnet_device->name, partid, bp); | ||
311 | break; | 285 | break; |
312 | 286 | ||
313 | default: | 287 | default: |
314 | spin_lock_bh(&xpnet_broadcast_lock); | 288 | spin_lock_bh(&xpnet_broadcast_lock); |
315 | xpnet_broadcast_partitions &= ~(1UL << (partid - 1)); | 289 | __clear_bit(partid, xpnet_broadcast_partitions); |
316 | bp = xpnet_broadcast_partitions; | ||
317 | spin_unlock_bh(&xpnet_broadcast_lock); | 290 | spin_unlock_bh(&xpnet_broadcast_lock); |
318 | 291 | ||
319 | if (bp == 0) | 292 | if (bitmap_empty((unsigned long *)xpnet_broadcast_partitions, |
293 | xp_max_npartitions)) { | ||
320 | netif_carrier_off(xpnet_device); | 294 | netif_carrier_off(xpnet_device); |
295 | } | ||
321 | 296 | ||
322 | dev_dbg(xpnet, "%s disconnected from partition %d; " | 297 | dev_dbg(xpnet, "%s disconnected from partition %d\n", |
323 | "xpnet_broadcast_partitions=0x%lx\n", | 298 | xpnet_device->name, partid); |
324 | xpnet_device->name, partid, bp); | ||
325 | break; | 299 | break; |
326 | |||
327 | } | 300 | } |
328 | } | 301 | } |
329 | 302 | ||
@@ -334,8 +307,10 @@ xpnet_dev_open(struct net_device *dev) | |||
334 | 307 | ||
335 | dev_dbg(xpnet, "calling xpc_connect(%d, 0x%p, NULL, %ld, %ld, %ld, " | 308 | dev_dbg(xpnet, "calling xpc_connect(%d, 0x%p, NULL, %ld, %ld, %ld, " |
336 | "%ld)\n", XPC_NET_CHANNEL, xpnet_connection_activity, | 309 | "%ld)\n", XPC_NET_CHANNEL, xpnet_connection_activity, |
337 | XPNET_MSG_SIZE, XPNET_MSG_NENTRIES, XPNET_MAX_KTHREADS, | 310 | (unsigned long)XPNET_MSG_SIZE, |
338 | XPNET_MAX_IDLE_KTHREADS); | 311 | (unsigned long)XPNET_MSG_NENTRIES, |
312 | (unsigned long)XPNET_MAX_KTHREADS, | ||
313 | (unsigned long)XPNET_MAX_IDLE_KTHREADS); | ||
339 | 314 | ||
340 | ret = xpc_connect(XPC_NET_CHANNEL, xpnet_connection_activity, NULL, | 315 | ret = xpc_connect(XPC_NET_CHANNEL, xpnet_connection_activity, NULL, |
341 | XPNET_MSG_SIZE, XPNET_MSG_NENTRIES, | 316 | XPNET_MSG_SIZE, XPNET_MSG_NENTRIES, |
@@ -426,35 +401,74 @@ xpnet_send_completed(enum xp_retval reason, short partid, int channel, | |||
426 | } | 401 | } |
427 | } | 402 | } |
428 | 403 | ||
404 | static void | ||
405 | xpnet_send(struct sk_buff *skb, struct xpnet_pending_msg *queued_msg, | ||
406 | u64 start_addr, u64 end_addr, u16 embedded_bytes, int dest_partid) | ||
407 | { | ||
408 | u8 msg_buffer[XPNET_MSG_SIZE]; | ||
409 | struct xpnet_message *msg = (struct xpnet_message *)&msg_buffer; | ||
410 | u16 msg_size = sizeof(struct xpnet_message); | ||
411 | enum xp_retval ret; | ||
412 | |||
413 | msg->embedded_bytes = embedded_bytes; | ||
414 | if (unlikely(embedded_bytes != 0)) { | ||
415 | msg->version = XPNET_VERSION_EMBED; | ||
416 | dev_dbg(xpnet, "calling memcpy(0x%p, 0x%p, 0x%lx)\n", | ||
417 | &msg->data, skb->data, (size_t)embedded_bytes); | ||
418 | skb_copy_from_linear_data(skb, &msg->data, | ||
419 | (size_t)embedded_bytes); | ||
420 | msg_size += embedded_bytes - 1; | ||
421 | } else { | ||
422 | msg->version = XPNET_VERSION; | ||
423 | } | ||
424 | msg->magic = XPNET_MAGIC; | ||
425 | msg->size = end_addr - start_addr; | ||
426 | msg->leadin_ignore = (u64)skb->data - start_addr; | ||
427 | msg->tailout_ignore = end_addr - (u64)skb_tail_pointer(skb); | ||
428 | msg->buf_pa = xp_pa((void *)start_addr); | ||
429 | |||
430 | dev_dbg(xpnet, "sending XPC message to %d:%d\n" | ||
431 | KERN_DEBUG "msg->buf_pa=0x%lx, msg->size=%u, " | ||
432 | "msg->leadin_ignore=%u, msg->tailout_ignore=%u\n", | ||
433 | dest_partid, XPC_NET_CHANNEL, msg->buf_pa, msg->size, | ||
434 | msg->leadin_ignore, msg->tailout_ignore); | ||
435 | |||
436 | atomic_inc(&queued_msg->use_count); | ||
437 | |||
438 | ret = xpc_send_notify(dest_partid, XPC_NET_CHANNEL, XPC_NOWAIT, msg, | ||
439 | msg_size, xpnet_send_completed, queued_msg); | ||
440 | if (unlikely(ret != xpSuccess)) | ||
441 | atomic_dec(&queued_msg->use_count); | ||
442 | } | ||
443 | |||
429 | /* | 444 | /* |
430 | * Network layer has formatted a packet (skb) and is ready to place it | 445 | * Network layer has formatted a packet (skb) and is ready to place it |
431 | * "on the wire". Prepare and send an xpnet_message to all partitions | 446 | * "on the wire". Prepare and send an xpnet_message to all partitions |
432 | * which have connected with us and are targets of this packet. | 447 | * which have connected with us and are targets of this packet. |
433 | * | 448 | * |
434 | * MAC-NOTE: For the XPNET driver, the MAC address contains the | 449 | * MAC-NOTE: For the XPNET driver, the MAC address contains the |
435 | * destination partition_id. If the destination partition id word | 450 | * destination partid. If the destination partid octets are 0xffff, |
436 | * is 0xff, this packet is to broadcast to all partitions. | 451 | * this packet is to be broadcast to all connected partitions. |
437 | */ | 452 | */ |
438 | static int | 453 | static int |
439 | xpnet_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) | 454 | xpnet_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) |
440 | { | 455 | { |
441 | struct xpnet_pending_msg *queued_msg; | 456 | struct xpnet_pending_msg *queued_msg; |
442 | enum xp_retval ret; | ||
443 | struct xpnet_message *msg; | ||
444 | u64 start_addr, end_addr; | 457 | u64 start_addr, end_addr; |
445 | long dp; | ||
446 | u8 second_mac_octet; | ||
447 | short dest_partid; | 458 | short dest_partid; |
448 | struct xpnet_dev_private *priv; | 459 | struct xpnet_dev_private *priv = (struct xpnet_dev_private *)dev->priv; |
449 | u16 embedded_bytes; | 460 | u16 embedded_bytes = 0; |
450 | |||
451 | priv = (struct xpnet_dev_private *)dev->priv; | ||
452 | 461 | ||
453 | dev_dbg(xpnet, ">skb->head=0x%p skb->data=0x%p skb->tail=0x%p " | 462 | dev_dbg(xpnet, ">skb->head=0x%p skb->data=0x%p skb->tail=0x%p " |
454 | "skb->end=0x%p skb->len=%d\n", (void *)skb->head, | 463 | "skb->end=0x%p skb->len=%d\n", (void *)skb->head, |
455 | (void *)skb->data, skb_tail_pointer(skb), skb_end_pointer(skb), | 464 | (void *)skb->data, skb_tail_pointer(skb), skb_end_pointer(skb), |
456 | skb->len); | 465 | skb->len); |
457 | 466 | ||
467 | if (skb->data[0] == 0x33) { | ||
468 | dev_kfree_skb(skb); | ||
469 | return 0; /* nothing needed to be done */ | ||
470 | } | ||
471 | |||
458 | /* | 472 | /* |
459 | * The xpnet_pending_msg tracks how many outstanding | 473 | * The xpnet_pending_msg tracks how many outstanding |
460 | * xpc_send_notifies are relying on this skb. When none | 474 | * xpc_send_notifies are relying on this skb. When none |
@@ -466,7 +480,6 @@ xpnet_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
466 | "packet\n", sizeof(struct xpnet_pending_msg)); | 480 | "packet\n", sizeof(struct xpnet_pending_msg)); |
467 | 481 | ||
468 | priv->stats.tx_errors++; | 482 | priv->stats.tx_errors++; |
469 | |||
470 | return -ENOMEM; | 483 | return -ENOMEM; |
471 | } | 484 | } |
472 | 485 | ||
@@ -475,7 +488,6 @@ xpnet_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
475 | end_addr = L1_CACHE_ALIGN((u64)skb_tail_pointer(skb)); | 488 | end_addr = L1_CACHE_ALIGN((u64)skb_tail_pointer(skb)); |
476 | 489 | ||
477 | /* calculate how many bytes to embed in the XPC message */ | 490 | /* calculate how many bytes to embed in the XPC message */ |
478 | embedded_bytes = 0; | ||
479 | if (unlikely(skb->len <= XPNET_MSG_DATA_MAX)) { | 491 | if (unlikely(skb->len <= XPNET_MSG_DATA_MAX)) { |
480 | /* skb->data does fit so embed */ | 492 | /* skb->data does fit so embed */ |
481 | embedded_bytes = skb->len; | 493 | embedded_bytes = skb->len; |
@@ -491,82 +503,28 @@ xpnet_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
491 | atomic_set(&queued_msg->use_count, 1); | 503 | atomic_set(&queued_msg->use_count, 1); |
492 | queued_msg->skb = skb; | 504 | queued_msg->skb = skb; |
493 | 505 | ||
494 | second_mac_octet = skb->data[XPNET_PARTID_OCTET]; | 506 | if (skb->data[0] == 0xff) { |
495 | if (second_mac_octet == 0xff) { | ||
496 | /* we are being asked to broadcast to all partitions */ | 507 | /* we are being asked to broadcast to all partitions */ |
497 | dp = xpnet_broadcast_partitions; | 508 | for_each_bit(dest_partid, xpnet_broadcast_partitions, |
498 | } else if (second_mac_octet != 0) { | 509 | xp_max_npartitions) { |
499 | dp = xpnet_broadcast_partitions & | ||
500 | (1UL << (second_mac_octet - 1)); | ||
501 | } else { | ||
502 | /* 0 is an invalid partid. Ignore */ | ||
503 | dp = 0; | ||
504 | } | ||
505 | dev_dbg(xpnet, "destination Partitions mask (dp) = 0x%lx\n", dp); | ||
506 | |||
507 | /* | ||
508 | * If we wanted to allow promiscuous mode to work like an | ||
509 | * unswitched network, this would be a good point to OR in a | ||
510 | * mask of partitions which should be receiving all packets. | ||
511 | */ | ||
512 | |||
513 | /* | ||
514 | * Main send loop. | ||
515 | */ | ||
516 | for (dest_partid = 1; dp && dest_partid < XP_MAX_PARTITIONS; | ||
517 | dest_partid++) { | ||
518 | 510 | ||
519 | if (!(dp & (1UL << (dest_partid - 1)))) { | 511 | xpnet_send(skb, queued_msg, start_addr, end_addr, |
520 | /* not destined for this partition */ | 512 | embedded_bytes, dest_partid); |
521 | continue; | ||
522 | } | 513 | } |
514 | } else { | ||
515 | dest_partid = (short)skb->data[XPNET_PARTID_OCTET + 1]; | ||
516 | dest_partid |= (short)skb->data[XPNET_PARTID_OCTET + 0] << 8; | ||
523 | 517 | ||
524 | /* remove this partition from the destinations mask */ | 518 | if (dest_partid >= 0 && |
525 | dp &= ~(1UL << (dest_partid - 1)); | 519 | dest_partid < xp_max_npartitions && |
526 | 520 | test_bit(dest_partid, xpnet_broadcast_partitions) != 0) { | |
527 | /* found a partition to send to */ | 521 | |
528 | 522 | xpnet_send(skb, queued_msg, start_addr, end_addr, | |
529 | ret = xpc_allocate(dest_partid, XPC_NET_CHANNEL, | 523 | embedded_bytes, dest_partid); |
530 | XPC_NOWAIT, (void **)&msg); | ||
531 | if (unlikely(ret != xpSuccess)) | ||
532 | continue; | ||
533 | |||
534 | msg->embedded_bytes = embedded_bytes; | ||
535 | if (unlikely(embedded_bytes != 0)) { | ||
536 | msg->version = XPNET_VERSION_EMBED; | ||
537 | dev_dbg(xpnet, "calling memcpy(0x%p, 0x%p, 0x%lx)\n", | ||
538 | &msg->data, skb->data, (size_t)embedded_bytes); | ||
539 | skb_copy_from_linear_data(skb, &msg->data, | ||
540 | (size_t)embedded_bytes); | ||
541 | } else { | ||
542 | msg->version = XPNET_VERSION; | ||
543 | } | ||
544 | msg->magic = XPNET_MAGIC; | ||
545 | msg->size = end_addr - start_addr; | ||
546 | msg->leadin_ignore = (u64)skb->data - start_addr; | ||
547 | msg->tailout_ignore = end_addr - (u64)skb_tail_pointer(skb); | ||
548 | msg->buf_pa = __pa(start_addr); | ||
549 | |||
550 | dev_dbg(xpnet, "sending XPC message to %d:%d\n" | ||
551 | KERN_DEBUG "msg->buf_pa=0x%lx, msg->size=%u, " | ||
552 | "msg->leadin_ignore=%u, msg->tailout_ignore=%u\n", | ||
553 | dest_partid, XPC_NET_CHANNEL, msg->buf_pa, msg->size, | ||
554 | msg->leadin_ignore, msg->tailout_ignore); | ||
555 | |||
556 | atomic_inc(&queued_msg->use_count); | ||
557 | |||
558 | ret = xpc_send_notify(dest_partid, XPC_NET_CHANNEL, msg, | ||
559 | xpnet_send_completed, queued_msg); | ||
560 | if (unlikely(ret != xpSuccess)) { | ||
561 | atomic_dec(&queued_msg->use_count); | ||
562 | continue; | ||
563 | } | 524 | } |
564 | } | 525 | } |
565 | 526 | ||
566 | if (atomic_dec_return(&queued_msg->use_count) == 0) { | 527 | if (atomic_dec_return(&queued_msg->use_count) == 0) { |
567 | dev_dbg(xpnet, "no partitions to receive packet destined for " | ||
568 | "%d\n", dest_partid); | ||
569 | |||
570 | dev_kfree_skb(skb); | 528 | dev_kfree_skb(skb); |
571 | kfree(queued_msg); | 529 | kfree(queued_msg); |
572 | } | 530 | } |
@@ -594,23 +552,28 @@ xpnet_dev_tx_timeout(struct net_device *dev) | |||
594 | static int __init | 552 | static int __init |
595 | xpnet_init(void) | 553 | xpnet_init(void) |
596 | { | 554 | { |
597 | int i; | 555 | int result; |
598 | u32 license_num; | ||
599 | int result = -ENOMEM; | ||
600 | 556 | ||
601 | if (!ia64_platform_is("sn2")) | 557 | if (!is_shub() && !is_uv()) |
602 | return -ENODEV; | 558 | return -ENODEV; |
603 | 559 | ||
604 | dev_info(xpnet, "registering network device %s\n", XPNET_DEVICE_NAME); | 560 | dev_info(xpnet, "registering network device %s\n", XPNET_DEVICE_NAME); |
605 | 561 | ||
562 | xpnet_broadcast_partitions = kzalloc(BITS_TO_LONGS(xp_max_npartitions) * | ||
563 | sizeof(long), GFP_KERNEL); | ||
564 | if (xpnet_broadcast_partitions == NULL) | ||
565 | return -ENOMEM; | ||
566 | |||
606 | /* | 567 | /* |
607 | * use ether_setup() to init the majority of our device | 568 | * use ether_setup() to init the majority of our device |
608 | * structure and then override the necessary pieces. | 569 | * structure and then override the necessary pieces. |
609 | */ | 570 | */ |
610 | xpnet_device = alloc_netdev(sizeof(struct xpnet_dev_private), | 571 | xpnet_device = alloc_netdev(sizeof(struct xpnet_dev_private), |
611 | XPNET_DEVICE_NAME, ether_setup); | 572 | XPNET_DEVICE_NAME, ether_setup); |
612 | if (xpnet_device == NULL) | 573 | if (xpnet_device == NULL) { |
574 | kfree(xpnet_broadcast_partitions); | ||
613 | return -ENOMEM; | 575 | return -ENOMEM; |
576 | } | ||
614 | 577 | ||
615 | netif_carrier_off(xpnet_device); | 578 | netif_carrier_off(xpnet_device); |
616 | 579 | ||
@@ -628,14 +591,10 @@ xpnet_init(void) | |||
628 | * MAC addresses. We chose the first octet of the MAC to be unlikely | 591 | * MAC addresses. We chose the first octet of the MAC to be unlikely |
629 | * to collide with any vendor's officially issued MAC. | 592 | * to collide with any vendor's officially issued MAC. |
630 | */ | 593 | */ |
631 | xpnet_device->dev_addr[0] = 0xfe; | 594 | xpnet_device->dev_addr[0] = 0x02; /* locally administered, no OUI */ |
632 | xpnet_device->dev_addr[XPNET_PARTID_OCTET] = sn_partition_id; | 595 | |
633 | license_num = sn_partition_serial_number_val(); | 596 | xpnet_device->dev_addr[XPNET_PARTID_OCTET + 1] = xp_partition_id; |
634 | for (i = 3; i >= 0; i--) { | 597 | xpnet_device->dev_addr[XPNET_PARTID_OCTET + 0] = (xp_partition_id >> 8); |
635 | xpnet_device->dev_addr[XPNET_LICENSE_OCTET + i] = | ||
636 | license_num & 0xff; | ||
637 | license_num = license_num >> 8; | ||
638 | } | ||
639 | 598 | ||
640 | /* | 599 | /* |
641 | * ether_setup() sets this to a multicast device. We are | 600 | * ether_setup() sets this to a multicast device. We are |
@@ -651,8 +610,10 @@ xpnet_init(void) | |||
651 | xpnet_device->features = NETIF_F_NO_CSUM; | 610 | xpnet_device->features = NETIF_F_NO_CSUM; |
652 | 611 | ||
653 | result = register_netdev(xpnet_device); | 612 | result = register_netdev(xpnet_device); |
654 | if (result != 0) | 613 | if (result != 0) { |
655 | free_netdev(xpnet_device); | 614 | free_netdev(xpnet_device); |
615 | kfree(xpnet_broadcast_partitions); | ||
616 | } | ||
656 | 617 | ||
657 | return result; | 618 | return result; |
658 | } | 619 | } |
@@ -666,8 +627,8 @@ xpnet_exit(void) | |||
666 | xpnet_device[0].name); | 627 | xpnet_device[0].name); |
667 | 628 | ||
668 | unregister_netdev(xpnet_device); | 629 | unregister_netdev(xpnet_device); |
669 | |||
670 | free_netdev(xpnet_device); | 630 | free_netdev(xpnet_device); |
631 | kfree(xpnet_broadcast_partitions); | ||
671 | } | 632 | } |
672 | 633 | ||
673 | module_exit(xpnet_exit); | 634 | module_exit(xpnet_exit); |