aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@woody.linux-foundation.org>2007-07-16 13:45:23 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-07-16 13:45:23 -0400
commit02b2318e07f98a7cdf7089a4457a8d62424aa824 (patch)
treeb40353a9ee6b034e21192ceb5df445fbc5fbdd32 /drivers
parentb91cba52e9b7b3f1c0037908a192d93a869ca9e5 (diff)
parentd54bc2793ec3405c6b8f217568a82b87bd8a591b (diff)
Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/sparc-2.6
* 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/sparc-2.6: (26 commits) [SPARC64]: Fix UP build. [SPARC64]: dr-cpu unconfigure support. [SERIAL]: Fix console write locking in sparc drivers. [SPARC64]: Give more accurate errors in dr_cpu_configure(). [SPARC64]: Clear cpu_{core,sibling}_map[] in smp_fill_in_sib_core_maps() [SPARC64]: Fix leak when DR added cpu does not bootup. [SPARC64]: Add ->set_affinity IRQ handlers. [SPARC64]: Process dr-cpu events in a kthread instead of workqueue. [SPARC64]: More sensible udelay implementation. [SPARC64]: SMP build fixes. [SPARC64]: mdesc.c needs linux/mm.h [SPARC64]: Fix build regressions added by dr-cpu changes. [SPARC64]: Unconditionally register vio_bus_type. [SPARC64]: Initial LDOM cpu hotplug support. [SPARC64]: Fix setting of variables in LDOM guest. [SPARC64]: Fix MD property lifetime bugs. [SPARC64]: Abstract out mdesc accesses for better MD update handling. [SPARC64]: Use more mearningful names for IRQ registry. [SPARC64]: Initial domain-services driver. [SPARC64]: Export powerd facilities for external entities. ...
Diffstat (limited to 'drivers')
-rw-r--r--drivers/block/Kconfig7
-rw-r--r--drivers/block/Makefile1
-rw-r--r--drivers/block/sunvdc.c972
-rw-r--r--drivers/net/Kconfig6
-rw-r--r--drivers/net/Makefile1
-rw-r--r--drivers/net/sunvnet.c1164
-rw-r--r--drivers/net/sunvnet.h70
-rw-r--r--drivers/serial/sunhv.c30
-rw-r--r--drivers/serial/sunsab.c19
-rw-r--r--drivers/serial/sunsu.c14
-rw-r--r--drivers/serial/sunzilog.c17
11 files changed, 2289 insertions, 12 deletions
diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig
index fd7a53bdcb63..e49162b15578 100644
--- a/drivers/block/Kconfig
+++ b/drivers/block/Kconfig
@@ -423,6 +423,13 @@ config ATA_OVER_ETH
423 This driver provides Support for ATA over Ethernet block 423 This driver provides Support for ATA over Ethernet block
424 devices like the Coraid EtherDrive (R) Storage Blade. 424 devices like the Coraid EtherDrive (R) Storage Blade.
425 425
426config SUNVDC
427 tristate "Sun Virtual Disk Client support"
428 depends on SUN_LDOMS
429 help
430 Support for virtual disk devices as a client under Sun
431 Logical Domains.
432
426source "drivers/s390/block/Kconfig" 433source "drivers/s390/block/Kconfig"
427 434
428endif # BLK_DEV 435endif # BLK_DEV
diff --git a/drivers/block/Makefile b/drivers/block/Makefile
index e5f98acc5d52..43371c59623e 100644
--- a/drivers/block/Makefile
+++ b/drivers/block/Makefile
@@ -19,6 +19,7 @@ obj-$(CONFIG_BLK_CPQ_DA) += cpqarray.o
19obj-$(CONFIG_BLK_CPQ_CISS_DA) += cciss.o 19obj-$(CONFIG_BLK_CPQ_CISS_DA) += cciss.o
20obj-$(CONFIG_BLK_DEV_DAC960) += DAC960.o 20obj-$(CONFIG_BLK_DEV_DAC960) += DAC960.o
21obj-$(CONFIG_CDROM_PKTCDVD) += pktcdvd.o 21obj-$(CONFIG_CDROM_PKTCDVD) += pktcdvd.o
22obj-$(CONFIG_SUNVDC) += sunvdc.o
22 23
23obj-$(CONFIG_BLK_DEV_UMEM) += umem.o 24obj-$(CONFIG_BLK_DEV_UMEM) += umem.o
24obj-$(CONFIG_BLK_DEV_NBD) += nbd.o 25obj-$(CONFIG_BLK_DEV_NBD) += nbd.o
diff --git a/drivers/block/sunvdc.c b/drivers/block/sunvdc.c
new file mode 100644
index 000000000000..0f5e3caf85d7
--- /dev/null
+++ b/drivers/block/sunvdc.c
@@ -0,0 +1,972 @@
1/* sunvdc.c: Sun LDOM Virtual Disk Client.
2 *
3 * Copyright (C) 2007 David S. Miller <davem@davemloft.net>
4 */
5
6#include <linux/module.h>
7#include <linux/kernel.h>
8#include <linux/types.h>
9#include <linux/blkdev.h>
10#include <linux/hdreg.h>
11#include <linux/genhd.h>
12#include <linux/slab.h>
13#include <linux/spinlock.h>
14#include <linux/completion.h>
15#include <linux/delay.h>
16#include <linux/init.h>
17#include <linux/list.h>
18
19#include <asm/vio.h>
20#include <asm/ldc.h>
21
22#define DRV_MODULE_NAME "sunvdc"
23#define PFX DRV_MODULE_NAME ": "
24#define DRV_MODULE_VERSION "1.0"
25#define DRV_MODULE_RELDATE "June 25, 2007"
26
27static char version[] __devinitdata =
28 DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
29MODULE_AUTHOR("David S. Miller (davem@davemloft.net)");
30MODULE_DESCRIPTION("Sun LDOM virtual disk client driver");
31MODULE_LICENSE("GPL");
32MODULE_VERSION(DRV_MODULE_VERSION);
33
34#define VDC_TX_RING_SIZE 256
35
36#define WAITING_FOR_LINK_UP 0x01
37#define WAITING_FOR_TX_SPACE 0x02
38#define WAITING_FOR_GEN_CMD 0x04
39#define WAITING_FOR_ANY -1
40
41struct vdc_req_entry {
42 struct request *req;
43};
44
45struct vdc_port {
46 struct vio_driver_state vio;
47
48 struct vdc *vp;
49
50 struct gendisk *disk;
51
52 struct vdc_completion *cmp;
53
54 u64 req_id;
55 u64 seq;
56 struct vdc_req_entry rq_arr[VDC_TX_RING_SIZE];
57
58 unsigned long ring_cookies;
59
60 u64 max_xfer_size;
61 u32 vdisk_block_size;
62
63 /* The server fills these in for us in the disk attribute
64 * ACK packet.
65 */
66 u64 operations;
67 u32 vdisk_size;
68 u8 vdisk_type;
69 u8 dev_no;
70
71 char disk_name[32];
72
73 struct vio_disk_geom geom;
74 struct vio_disk_vtoc label;
75
76 struct list_head list;
77};
78
79static inline struct vdc_port *to_vdc_port(struct vio_driver_state *vio)
80{
81 return container_of(vio, struct vdc_port, vio);
82}
83
84struct vdc {
85 /* Protects prot_list. */
86 spinlock_t lock;
87
88 struct vio_dev *dev;
89
90 struct list_head port_list;
91};
92
93/* Ordered from largest major to lowest */
94static struct vio_version vdc_versions[] = {
95 { .major = 1, .minor = 0 },
96};
97
98#define VDCBLK_NAME "vdisk"
99static int vdc_major;
100#define PARTITION_SHIFT 3
101
102static inline u32 vdc_tx_dring_avail(struct vio_dring_state *dr)
103{
104 return vio_dring_avail(dr, VDC_TX_RING_SIZE);
105}
106
107static int vdc_getgeo(struct block_device *bdev, struct hd_geometry *geo)
108{
109 struct gendisk *disk = bdev->bd_disk;
110 struct vdc_port *port = disk->private_data;
111
112 geo->heads = (u8) port->geom.num_hd;
113 geo->sectors = (u8) port->geom.num_sec;
114 geo->cylinders = port->geom.num_cyl;
115
116 return 0;
117}
118
119static struct block_device_operations vdc_fops = {
120 .owner = THIS_MODULE,
121 .getgeo = vdc_getgeo,
122};
123
124static void vdc_finish(struct vio_driver_state *vio, int err, int waiting_for)
125{
126 if (vio->cmp &&
127 (waiting_for == -1 ||
128 vio->cmp->waiting_for == waiting_for)) {
129 vio->cmp->err = err;
130 complete(&vio->cmp->com);
131 vio->cmp = NULL;
132 }
133}
134
135static void vdc_handshake_complete(struct vio_driver_state *vio)
136{
137 vdc_finish(vio, 0, WAITING_FOR_LINK_UP);
138}
139
140static int vdc_handle_unknown(struct vdc_port *port, void *arg)
141{
142 struct vio_msg_tag *pkt = arg;
143
144 printk(KERN_ERR PFX "Received unknown msg [%02x:%02x:%04x:%08x]\n",
145 pkt->type, pkt->stype, pkt->stype_env, pkt->sid);
146 printk(KERN_ERR PFX "Resetting connection.\n");
147
148 ldc_disconnect(port->vio.lp);
149
150 return -ECONNRESET;
151}
152
153static int vdc_send_attr(struct vio_driver_state *vio)
154{
155 struct vdc_port *port = to_vdc_port(vio);
156 struct vio_disk_attr_info pkt;
157
158 memset(&pkt, 0, sizeof(pkt));
159
160 pkt.tag.type = VIO_TYPE_CTRL;
161 pkt.tag.stype = VIO_SUBTYPE_INFO;
162 pkt.tag.stype_env = VIO_ATTR_INFO;
163 pkt.tag.sid = vio_send_sid(vio);
164
165 pkt.xfer_mode = VIO_DRING_MODE;
166 pkt.vdisk_block_size = port->vdisk_block_size;
167 pkt.max_xfer_size = port->max_xfer_size;
168
169 viodbg(HS, "SEND ATTR xfer_mode[0x%x] blksz[%u] max_xfer[%lu]\n",
170 pkt.xfer_mode, pkt.vdisk_block_size, pkt.max_xfer_size);
171
172 return vio_ldc_send(&port->vio, &pkt, sizeof(pkt));
173}
174
175static int vdc_handle_attr(struct vio_driver_state *vio, void *arg)
176{
177 struct vdc_port *port = to_vdc_port(vio);
178 struct vio_disk_attr_info *pkt = arg;
179
180 viodbg(HS, "GOT ATTR stype[0x%x] ops[%lx] disk_size[%lu] disk_type[%x] "
181 "xfer_mode[0x%x] blksz[%u] max_xfer[%lu]\n",
182 pkt->tag.stype, pkt->operations,
183 pkt->vdisk_size, pkt->vdisk_type,
184 pkt->xfer_mode, pkt->vdisk_block_size,
185 pkt->max_xfer_size);
186
187 if (pkt->tag.stype == VIO_SUBTYPE_ACK) {
188 switch (pkt->vdisk_type) {
189 case VD_DISK_TYPE_DISK:
190 case VD_DISK_TYPE_SLICE:
191 break;
192
193 default:
194 printk(KERN_ERR PFX "%s: Bogus vdisk_type 0x%x\n",
195 vio->name, pkt->vdisk_type);
196 return -ECONNRESET;
197 }
198
199 if (pkt->vdisk_block_size > port->vdisk_block_size) {
200 printk(KERN_ERR PFX "%s: BLOCK size increased "
201 "%u --> %u\n",
202 vio->name,
203 port->vdisk_block_size, pkt->vdisk_block_size);
204 return -ECONNRESET;
205 }
206
207 port->operations = pkt->operations;
208 port->vdisk_size = pkt->vdisk_size;
209 port->vdisk_type = pkt->vdisk_type;
210 if (pkt->max_xfer_size < port->max_xfer_size)
211 port->max_xfer_size = pkt->max_xfer_size;
212 port->vdisk_block_size = pkt->vdisk_block_size;
213 return 0;
214 } else {
215 printk(KERN_ERR PFX "%s: Attribute NACK\n", vio->name);
216
217 return -ECONNRESET;
218 }
219}
220
221static void vdc_end_special(struct vdc_port *port, struct vio_disk_desc *desc)
222{
223 int err = desc->status;
224
225 vdc_finish(&port->vio, -err, WAITING_FOR_GEN_CMD);
226}
227
228static void vdc_end_request(struct request *req, int uptodate, int num_sectors)
229{
230 if (end_that_request_first(req, uptodate, num_sectors))
231 return;
232 add_disk_randomness(req->rq_disk);
233 end_that_request_last(req, uptodate);
234}
235
236static void vdc_end_one(struct vdc_port *port, struct vio_dring_state *dr,
237 unsigned int index)
238{
239 struct vio_disk_desc *desc = vio_dring_entry(dr, index);
240 struct vdc_req_entry *rqe = &port->rq_arr[index];
241 struct request *req;
242
243 if (unlikely(desc->hdr.state != VIO_DESC_DONE))
244 return;
245
246 ldc_unmap(port->vio.lp, desc->cookies, desc->ncookies);
247 desc->hdr.state = VIO_DESC_FREE;
248 dr->cons = (index + 1) & (VDC_TX_RING_SIZE - 1);
249
250 req = rqe->req;
251 if (req == NULL) {
252 vdc_end_special(port, desc);
253 return;
254 }
255
256 rqe->req = NULL;
257
258 vdc_end_request(req, !desc->status, desc->size >> 9);
259
260 if (blk_queue_stopped(port->disk->queue))
261 blk_start_queue(port->disk->queue);
262}
263
264static int vdc_ack(struct vdc_port *port, void *msgbuf)
265{
266 struct vio_dring_state *dr = &port->vio.drings[VIO_DRIVER_TX_RING];
267 struct vio_dring_data *pkt = msgbuf;
268
269 if (unlikely(pkt->dring_ident != dr->ident ||
270 pkt->start_idx != pkt->end_idx ||
271 pkt->start_idx >= VDC_TX_RING_SIZE))
272 return 0;
273
274 vdc_end_one(port, dr, pkt->start_idx);
275
276 return 0;
277}
278
279static int vdc_nack(struct vdc_port *port, void *msgbuf)
280{
281 /* XXX Implement me XXX */
282 return 0;
283}
284
285static void vdc_event(void *arg, int event)
286{
287 struct vdc_port *port = arg;
288 struct vio_driver_state *vio = &port->vio;
289 unsigned long flags;
290 int err;
291
292 spin_lock_irqsave(&vio->lock, flags);
293
294 if (unlikely(event == LDC_EVENT_RESET ||
295 event == LDC_EVENT_UP)) {
296 vio_link_state_change(vio, event);
297 spin_unlock_irqrestore(&vio->lock, flags);
298 return;
299 }
300
301 if (unlikely(event != LDC_EVENT_DATA_READY)) {
302 printk(KERN_WARNING PFX "Unexpected LDC event %d\n", event);
303 spin_unlock_irqrestore(&vio->lock, flags);
304 return;
305 }
306
307 err = 0;
308 while (1) {
309 union {
310 struct vio_msg_tag tag;
311 u64 raw[8];
312 } msgbuf;
313
314 err = ldc_read(vio->lp, &msgbuf, sizeof(msgbuf));
315 if (unlikely(err < 0)) {
316 if (err == -ECONNRESET)
317 vio_conn_reset(vio);
318 break;
319 }
320 if (err == 0)
321 break;
322 viodbg(DATA, "TAG [%02x:%02x:%04x:%08x]\n",
323 msgbuf.tag.type,
324 msgbuf.tag.stype,
325 msgbuf.tag.stype_env,
326 msgbuf.tag.sid);
327 err = vio_validate_sid(vio, &msgbuf.tag);
328 if (err < 0)
329 break;
330
331 if (likely(msgbuf.tag.type == VIO_TYPE_DATA)) {
332 if (msgbuf.tag.stype == VIO_SUBTYPE_ACK)
333 err = vdc_ack(port, &msgbuf);
334 else if (msgbuf.tag.stype == VIO_SUBTYPE_NACK)
335 err = vdc_nack(port, &msgbuf);
336 else
337 err = vdc_handle_unknown(port, &msgbuf);
338 } else if (msgbuf.tag.type == VIO_TYPE_CTRL) {
339 err = vio_control_pkt_engine(vio, &msgbuf);
340 } else {
341 err = vdc_handle_unknown(port, &msgbuf);
342 }
343 if (err < 0)
344 break;
345 }
346 if (err < 0)
347 vdc_finish(&port->vio, err, WAITING_FOR_ANY);
348 spin_unlock_irqrestore(&vio->lock, flags);
349}
350
351static int __vdc_tx_trigger(struct vdc_port *port)
352{
353 struct vio_dring_state *dr = &port->vio.drings[VIO_DRIVER_TX_RING];
354 struct vio_dring_data hdr = {
355 .tag = {
356 .type = VIO_TYPE_DATA,
357 .stype = VIO_SUBTYPE_INFO,
358 .stype_env = VIO_DRING_DATA,
359 .sid = vio_send_sid(&port->vio),
360 },
361 .dring_ident = dr->ident,
362 .start_idx = dr->prod,
363 .end_idx = dr->prod,
364 };
365 int err, delay;
366
367 hdr.seq = dr->snd_nxt;
368 delay = 1;
369 do {
370 err = vio_ldc_send(&port->vio, &hdr, sizeof(hdr));
371 if (err > 0) {
372 dr->snd_nxt++;
373 break;
374 }
375 udelay(delay);
376 if ((delay <<= 1) > 128)
377 delay = 128;
378 } while (err == -EAGAIN);
379
380 return err;
381}
382
383static int __send_request(struct request *req)
384{
385 struct vdc_port *port = req->rq_disk->private_data;
386 struct vio_dring_state *dr = &port->vio.drings[VIO_DRIVER_TX_RING];
387 struct scatterlist sg[port->ring_cookies];
388 struct vdc_req_entry *rqe;
389 struct vio_disk_desc *desc;
390 unsigned int map_perm;
391 int nsg, err, i;
392 u64 len;
393 u8 op;
394
395 map_perm = LDC_MAP_SHADOW | LDC_MAP_DIRECT | LDC_MAP_IO;
396
397 if (rq_data_dir(req) == READ) {
398 map_perm |= LDC_MAP_W;
399 op = VD_OP_BREAD;
400 } else {
401 map_perm |= LDC_MAP_R;
402 op = VD_OP_BWRITE;
403 }
404
405 nsg = blk_rq_map_sg(req->q, req, sg);
406
407 len = 0;
408 for (i = 0; i < nsg; i++)
409 len += sg[i].length;
410
411 if (unlikely(vdc_tx_dring_avail(dr) < 1)) {
412 blk_stop_queue(port->disk->queue);
413 err = -ENOMEM;
414 goto out;
415 }
416
417 desc = vio_dring_cur(dr);
418
419 err = ldc_map_sg(port->vio.lp, sg, nsg,
420 desc->cookies, port->ring_cookies,
421 map_perm);
422 if (err < 0) {
423 printk(KERN_ERR PFX "ldc_map_sg() failure, err=%d.\n", err);
424 return err;
425 }
426
427 rqe = &port->rq_arr[dr->prod];
428 rqe->req = req;
429
430 desc->hdr.ack = VIO_ACK_ENABLE;
431 desc->req_id = port->req_id;
432 desc->operation = op;
433 if (port->vdisk_type == VD_DISK_TYPE_DISK) {
434 desc->slice = 2;
435 } else {
436 desc->slice = 0;
437 }
438 desc->status = ~0;
439 desc->offset = (req->sector << 9) / port->vdisk_block_size;
440 desc->size = len;
441 desc->ncookies = err;
442
443 /* This has to be a non-SMP write barrier because we are writing
444 * to memory which is shared with the peer LDOM.
445 */
446 wmb();
447 desc->hdr.state = VIO_DESC_READY;
448
449 err = __vdc_tx_trigger(port);
450 if (err < 0) {
451 printk(KERN_ERR PFX "vdc_tx_trigger() failure, err=%d\n", err);
452 } else {
453 port->req_id++;
454 dr->prod = (dr->prod + 1) & (VDC_TX_RING_SIZE - 1);
455 }
456out:
457
458 return err;
459}
460
461static void do_vdc_request(request_queue_t *q)
462{
463 while (1) {
464 struct request *req = elv_next_request(q);
465
466 if (!req)
467 break;
468
469 blkdev_dequeue_request(req);
470 if (__send_request(req) < 0)
471 vdc_end_request(req, 0, req->hard_nr_sectors);
472 }
473}
474
475static int generic_request(struct vdc_port *port, u8 op, void *buf, int len)
476{
477 struct vio_dring_state *dr;
478 struct vio_completion comp;
479 struct vio_disk_desc *desc;
480 unsigned int map_perm;
481 unsigned long flags;
482 int op_len, err;
483 void *req_buf;
484
485 if (!(((u64)1 << ((u64)op - 1)) & port->operations))
486 return -EOPNOTSUPP;
487
488 switch (op) {
489 case VD_OP_BREAD:
490 case VD_OP_BWRITE:
491 default:
492 return -EINVAL;
493
494 case VD_OP_FLUSH:
495 op_len = 0;
496 map_perm = 0;
497 break;
498
499 case VD_OP_GET_WCE:
500 op_len = sizeof(u32);
501 map_perm = LDC_MAP_W;
502 break;
503
504 case VD_OP_SET_WCE:
505 op_len = sizeof(u32);
506 map_perm = LDC_MAP_R;
507 break;
508
509 case VD_OP_GET_VTOC:
510 op_len = sizeof(struct vio_disk_vtoc);
511 map_perm = LDC_MAP_W;
512 break;
513
514 case VD_OP_SET_VTOC:
515 op_len = sizeof(struct vio_disk_vtoc);
516 map_perm = LDC_MAP_R;
517 break;
518
519 case VD_OP_GET_DISKGEOM:
520 op_len = sizeof(struct vio_disk_geom);
521 map_perm = LDC_MAP_W;
522 break;
523
524 case VD_OP_SET_DISKGEOM:
525 op_len = sizeof(struct vio_disk_geom);
526 map_perm = LDC_MAP_R;
527 break;
528
529 case VD_OP_SCSICMD:
530 op_len = 16;
531 map_perm = LDC_MAP_RW;
532 break;
533
534 case VD_OP_GET_DEVID:
535 op_len = sizeof(struct vio_disk_devid);
536 map_perm = LDC_MAP_W;
537 break;
538
539 case VD_OP_GET_EFI:
540 case VD_OP_SET_EFI:
541 return -EOPNOTSUPP;
542 break;
543 };
544
545 map_perm |= LDC_MAP_SHADOW | LDC_MAP_DIRECT | LDC_MAP_IO;
546
547 op_len = (op_len + 7) & ~7;
548 req_buf = kzalloc(op_len, GFP_KERNEL);
549 if (!req_buf)
550 return -ENOMEM;
551
552 if (len > op_len)
553 len = op_len;
554
555 if (map_perm & LDC_MAP_R)
556 memcpy(req_buf, buf, len);
557
558 spin_lock_irqsave(&port->vio.lock, flags);
559
560 dr = &port->vio.drings[VIO_DRIVER_TX_RING];
561
562 /* XXX If we want to use this code generically we have to
563 * XXX handle TX ring exhaustion etc.
564 */
565 desc = vio_dring_cur(dr);
566
567 err = ldc_map_single(port->vio.lp, req_buf, op_len,
568 desc->cookies, port->ring_cookies,
569 map_perm);
570 if (err < 0) {
571 spin_unlock_irqrestore(&port->vio.lock, flags);
572 kfree(req_buf);
573 return err;
574 }
575
576 init_completion(&comp.com);
577 comp.waiting_for = WAITING_FOR_GEN_CMD;
578 port->vio.cmp = &comp;
579
580 desc->hdr.ack = VIO_ACK_ENABLE;
581 desc->req_id = port->req_id;
582 desc->operation = op;
583 desc->slice = 0;
584 desc->status = ~0;
585 desc->offset = 0;
586 desc->size = op_len;
587 desc->ncookies = err;
588
589 /* This has to be a non-SMP write barrier because we are writing
590 * to memory which is shared with the peer LDOM.
591 */
592 wmb();
593 desc->hdr.state = VIO_DESC_READY;
594
595 err = __vdc_tx_trigger(port);
596 if (err >= 0) {
597 port->req_id++;
598 dr->prod = (dr->prod + 1) & (VDC_TX_RING_SIZE - 1);
599 spin_unlock_irqrestore(&port->vio.lock, flags);
600
601 wait_for_completion(&comp.com);
602 err = comp.err;
603 } else {
604 port->vio.cmp = NULL;
605 spin_unlock_irqrestore(&port->vio.lock, flags);
606 }
607
608 if (map_perm & LDC_MAP_W)
609 memcpy(buf, req_buf, len);
610
611 kfree(req_buf);
612
613 return err;
614}
615
616static int __devinit vdc_alloc_tx_ring(struct vdc_port *port)
617{
618 struct vio_dring_state *dr = &port->vio.drings[VIO_DRIVER_TX_RING];
619 unsigned long len, entry_size;
620 int ncookies;
621 void *dring;
622
623 entry_size = sizeof(struct vio_disk_desc) +
624 (sizeof(struct ldc_trans_cookie) * port->ring_cookies);
625 len = (VDC_TX_RING_SIZE * entry_size);
626
627 ncookies = VIO_MAX_RING_COOKIES;
628 dring = ldc_alloc_exp_dring(port->vio.lp, len,
629 dr->cookies, &ncookies,
630 (LDC_MAP_SHADOW |
631 LDC_MAP_DIRECT |
632 LDC_MAP_RW));
633 if (IS_ERR(dring))
634 return PTR_ERR(dring);
635
636 dr->base = dring;
637 dr->entry_size = entry_size;
638 dr->num_entries = VDC_TX_RING_SIZE;
639 dr->prod = dr->cons = 0;
640 dr->pending = VDC_TX_RING_SIZE;
641 dr->ncookies = ncookies;
642
643 return 0;
644}
645
646static void vdc_free_tx_ring(struct vdc_port *port)
647{
648 struct vio_dring_state *dr = &port->vio.drings[VIO_DRIVER_TX_RING];
649
650 if (dr->base) {
651 ldc_free_exp_dring(port->vio.lp, dr->base,
652 (dr->entry_size * dr->num_entries),
653 dr->cookies, dr->ncookies);
654 dr->base = NULL;
655 dr->entry_size = 0;
656 dr->num_entries = 0;
657 dr->pending = 0;
658 dr->ncookies = 0;
659 }
660}
661
662static int probe_disk(struct vdc_port *port)
663{
664 struct vio_completion comp;
665 struct request_queue *q;
666 struct gendisk *g;
667 int err;
668
669 init_completion(&comp.com);
670 comp.err = 0;
671 comp.waiting_for = WAITING_FOR_LINK_UP;
672 port->vio.cmp = &comp;
673
674 vio_port_up(&port->vio);
675
676 wait_for_completion(&comp.com);
677 if (comp.err)
678 return comp.err;
679
680 err = generic_request(port, VD_OP_GET_VTOC,
681 &port->label, sizeof(port->label));
682 if (err < 0) {
683 printk(KERN_ERR PFX "VD_OP_GET_VTOC returns error %d\n", err);
684 return err;
685 }
686
687 err = generic_request(port, VD_OP_GET_DISKGEOM,
688 &port->geom, sizeof(port->geom));
689 if (err < 0) {
690 printk(KERN_ERR PFX "VD_OP_GET_DISKGEOM returns "
691 "error %d\n", err);
692 return err;
693 }
694
695 port->vdisk_size = ((u64)port->geom.num_cyl *
696 (u64)port->geom.num_hd *
697 (u64)port->geom.num_sec);
698
699 q = blk_init_queue(do_vdc_request, &port->vio.lock);
700 if (!q) {
701 printk(KERN_ERR PFX "%s: Could not allocate queue.\n",
702 port->vio.name);
703 return -ENOMEM;
704 }
705 g = alloc_disk(1 << PARTITION_SHIFT);
706 if (!g) {
707 printk(KERN_ERR PFX "%s: Could not allocate gendisk.\n",
708 port->vio.name);
709 blk_cleanup_queue(q);
710 return -ENOMEM;
711 }
712
713 port->disk = g;
714
715 blk_queue_max_hw_segments(q, port->ring_cookies);
716 blk_queue_max_phys_segments(q, port->ring_cookies);
717 blk_queue_max_sectors(q, port->max_xfer_size);
718 g->major = vdc_major;
719 g->first_minor = port->dev_no << PARTITION_SHIFT;
720 strcpy(g->disk_name, port->disk_name);
721
722 g->fops = &vdc_fops;
723 g->queue = q;
724 g->private_data = port;
725 g->driverfs_dev = &port->vio.vdev->dev;
726
727 set_capacity(g, port->vdisk_size);
728
729 printk(KERN_INFO PFX "%s: %u sectors (%u MB)\n",
730 g->disk_name,
731 port->vdisk_size, (port->vdisk_size >> (20 - 9)));
732
733 add_disk(g);
734
735 return 0;
736}
737
738static struct ldc_channel_config vdc_ldc_cfg = {
739 .event = vdc_event,
740 .mtu = 64,
741 .mode = LDC_MODE_UNRELIABLE,
742};
743
744static struct vio_driver_ops vdc_vio_ops = {
745 .send_attr = vdc_send_attr,
746 .handle_attr = vdc_handle_attr,
747 .handshake_complete = vdc_handshake_complete,
748};
749
750static int __devinit vdc_port_probe(struct vio_dev *vdev,
751 const struct vio_device_id *id)
752{
753 struct mdesc_handle *hp;
754 struct vdc_port *port;
755 unsigned long flags;
756 struct vdc *vp;
757 const u64 *port_id;
758 int err;
759
760 vp = dev_get_drvdata(vdev->dev.parent);
761 if (!vp) {
762 printk(KERN_ERR PFX "Cannot find port parent vdc.\n");
763 return -ENODEV;
764 }
765
766 hp = mdesc_grab();
767
768 port_id = mdesc_get_property(hp, vdev->mp, "id", NULL);
769 err = -ENODEV;
770 if (!port_id) {
771 printk(KERN_ERR PFX "Port lacks id property.\n");
772 goto err_out_release_mdesc;
773 }
774 if ((*port_id << PARTITION_SHIFT) & ~(u64)MINORMASK) {
775 printk(KERN_ERR PFX "Port id [%lu] too large.\n", *port_id);
776 goto err_out_release_mdesc;
777 }
778
779 port = kzalloc(sizeof(*port), GFP_KERNEL);
780 err = -ENOMEM;
781 if (!port) {
782 printk(KERN_ERR PFX "Cannot allocate vdc_port.\n");
783 goto err_out_release_mdesc;
784 }
785
786 port->vp = vp;
787 port->dev_no = *port_id;
788
789 if (port->dev_no >= 26)
790 snprintf(port->disk_name, sizeof(port->disk_name),
791 VDCBLK_NAME "%c%c",
792 'a' + (port->dev_no / 26) - 1,
793 'a' + (port->dev_no % 26));
794 else
795 snprintf(port->disk_name, sizeof(port->disk_name),
796 VDCBLK_NAME "%c", 'a' + (port->dev_no % 26));
797
798 err = vio_driver_init(&port->vio, vdev, VDEV_DISK,
799 vdc_versions, ARRAY_SIZE(vdc_versions),
800 &vdc_vio_ops, port->disk_name);
801 if (err)
802 goto err_out_free_port;
803
804 port->vdisk_block_size = 512;
805 port->max_xfer_size = ((128 * 1024) / port->vdisk_block_size);
806 port->ring_cookies = ((port->max_xfer_size *
807 port->vdisk_block_size) / PAGE_SIZE) + 2;
808
809 err = vio_ldc_alloc(&port->vio, &vdc_ldc_cfg, port);
810 if (err)
811 goto err_out_free_port;
812
813 err = vdc_alloc_tx_ring(port);
814 if (err)
815 goto err_out_free_ldc;
816
817 err = probe_disk(port);
818 if (err)
819 goto err_out_free_tx_ring;
820
821 INIT_LIST_HEAD(&port->list);
822
823 spin_lock_irqsave(&vp->lock, flags);
824 list_add(&port->list, &vp->port_list);
825 spin_unlock_irqrestore(&vp->lock, flags);
826
827 dev_set_drvdata(&vdev->dev, port);
828
829 mdesc_release(hp);
830
831 return 0;
832
833err_out_free_tx_ring:
834 vdc_free_tx_ring(port);
835
836err_out_free_ldc:
837 vio_ldc_free(&port->vio);
838
839err_out_free_port:
840 kfree(port);
841
842err_out_release_mdesc:
843 mdesc_release(hp);
844 return err;
845}
846
847static int vdc_port_remove(struct vio_dev *vdev)
848{
849 struct vdc_port *port = dev_get_drvdata(&vdev->dev);
850
851 if (port) {
852 del_timer_sync(&port->vio.timer);
853
854 vdc_free_tx_ring(port);
855 vio_ldc_free(&port->vio);
856
857 dev_set_drvdata(&vdev->dev, NULL);
858
859 kfree(port);
860 }
861 return 0;
862}
863
864static struct vio_device_id vdc_port_match[] = {
865 {
866 .type = "vdc-port",
867 },
868 {},
869};
870MODULE_DEVICE_TABLE(vio, vdc_match);
871
872static struct vio_driver vdc_port_driver = {
873 .id_table = vdc_port_match,
874 .probe = vdc_port_probe,
875 .remove = vdc_port_remove,
876 .driver = {
877 .name = "vdc_port",
878 .owner = THIS_MODULE,
879 }
880};
881
882static int __devinit vdc_probe(struct vio_dev *vdev,
883 const struct vio_device_id *id)
884{
885 static int vdc_version_printed;
886 struct vdc *vp;
887
888 if (vdc_version_printed++ == 0)
889 printk(KERN_INFO "%s", version);
890
891 vp = kzalloc(sizeof(struct vdc), GFP_KERNEL);
892 if (!vp)
893 return -ENOMEM;
894
895 spin_lock_init(&vp->lock);
896 vp->dev = vdev;
897 INIT_LIST_HEAD(&vp->port_list);
898
899 dev_set_drvdata(&vdev->dev, vp);
900
901 return 0;
902}
903
904static int vdc_remove(struct vio_dev *vdev)
905{
906
907 struct vdc *vp = dev_get_drvdata(&vdev->dev);
908
909 if (vp) {
910 kfree(vp);
911 dev_set_drvdata(&vdev->dev, NULL);
912 }
913 return 0;
914}
915
916static struct vio_device_id vdc_match[] = {
917 {
918 .type = "block",
919 },
920 {},
921};
922MODULE_DEVICE_TABLE(vio, vdc_match);
923
924static struct vio_driver vdc_driver = {
925 .id_table = vdc_match,
926 .probe = vdc_probe,
927 .remove = vdc_remove,
928 .driver = {
929 .name = "vdc",
930 .owner = THIS_MODULE,
931 }
932};
933
934static int __init vdc_init(void)
935{
936 int err;
937
938 err = register_blkdev(0, VDCBLK_NAME);
939 if (err < 0)
940 goto out_err;
941
942 vdc_major = err;
943 err = vio_register_driver(&vdc_driver);
944 if (err)
945 goto out_unregister_blkdev;
946
947 err = vio_register_driver(&vdc_port_driver);
948 if (err)
949 goto out_unregister_vdc;
950
951 return 0;
952
953out_unregister_vdc:
954 vio_unregister_driver(&vdc_driver);
955
956out_unregister_blkdev:
957 unregister_blkdev(vdc_major, VDCBLK_NAME);
958 vdc_major = 0;
959
960out_err:
961 return err;
962}
963
964static void __exit vdc_exit(void)
965{
966 vio_unregister_driver(&vdc_port_driver);
967 vio_unregister_driver(&vdc_driver);
968 unregister_blkdev(vdc_major, VDCBLK_NAME);
969}
970
971module_init(vdc_init);
972module_exit(vdc_exit);
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index d17d64eb7065..7903f9c7839e 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -604,6 +604,12 @@ config CASSINI
604 Support for the Sun Cassini chip, aka Sun GigaSwift Ethernet. See also 604 Support for the Sun Cassini chip, aka Sun GigaSwift Ethernet. See also
605 <http://www.sun.com/products-n-solutions/hardware/docs/pdf/817-4341-10.pdf> 605 <http://www.sun.com/products-n-solutions/hardware/docs/pdf/817-4341-10.pdf>
606 606
607config SUNVNET
608 tristate "Sun Virtual Network support"
609 depends on SUN_LDOMS
610 help
611 Support for virtual network devices under Sun Logical Domains.
612
607config NET_VENDOR_3COM 613config NET_VENDOR_3COM
608 bool "3COM cards" 614 bool "3COM cards"
609 depends on ISA || EISA || MCA || PCI 615 depends on ISA || EISA || MCA || PCI
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index c26b8674213c..b95b1b237a26 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -34,6 +34,7 @@ obj-$(CONFIG_SUNBMAC) += sunbmac.o
34obj-$(CONFIG_MYRI_SBUS) += myri_sbus.o 34obj-$(CONFIG_MYRI_SBUS) += myri_sbus.o
35obj-$(CONFIG_SUNGEM) += sungem.o sungem_phy.o 35obj-$(CONFIG_SUNGEM) += sungem.o sungem_phy.o
36obj-$(CONFIG_CASSINI) += cassini.o 36obj-$(CONFIG_CASSINI) += cassini.o
37obj-$(CONFIG_SUNVNET) += sunvnet.o
37 38
38obj-$(CONFIG_MACE) += mace.o 39obj-$(CONFIG_MACE) += mace.o
39obj-$(CONFIG_BMAC) += bmac.o 40obj-$(CONFIG_BMAC) += bmac.o
diff --git a/drivers/net/sunvnet.c b/drivers/net/sunvnet.c
new file mode 100644
index 000000000000..8a667c13faef
--- /dev/null
+++ b/drivers/net/sunvnet.c
@@ -0,0 +1,1164 @@
1/* sunvnet.c: Sun LDOM Virtual Network Driver.
2 *
3 * Copyright (C) 2007 David S. Miller <davem@davemloft.net>
4 */
5
6#include <linux/module.h>
7#include <linux/kernel.h>
8#include <linux/types.h>
9#include <linux/slab.h>
10#include <linux/delay.h>
11#include <linux/init.h>
12#include <linux/netdevice.h>
13#include <linux/ethtool.h>
14#include <linux/etherdevice.h>
15
16#include <asm/vio.h>
17#include <asm/ldc.h>
18
19#include "sunvnet.h"
20
21#define DRV_MODULE_NAME "sunvnet"
22#define PFX DRV_MODULE_NAME ": "
23#define DRV_MODULE_VERSION "1.0"
24#define DRV_MODULE_RELDATE "June 25, 2007"
25
26static char version[] __devinitdata =
27 DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
28MODULE_AUTHOR("David S. Miller (davem@davemloft.net)");
29MODULE_DESCRIPTION("Sun LDOM virtual network driver");
30MODULE_LICENSE("GPL");
31MODULE_VERSION(DRV_MODULE_VERSION);
32
33/* Ordered from largest major to lowest */
34static struct vio_version vnet_versions[] = {
35 { .major = 1, .minor = 0 },
36};
37
38static inline u32 vnet_tx_dring_avail(struct vio_dring_state *dr)
39{
40 return vio_dring_avail(dr, VNET_TX_RING_SIZE);
41}
42
43static int vnet_handle_unknown(struct vnet_port *port, void *arg)
44{
45 struct vio_msg_tag *pkt = arg;
46
47 printk(KERN_ERR PFX "Received unknown msg [%02x:%02x:%04x:%08x]\n",
48 pkt->type, pkt->stype, pkt->stype_env, pkt->sid);
49 printk(KERN_ERR PFX "Resetting connection.\n");
50
51 ldc_disconnect(port->vio.lp);
52
53 return -ECONNRESET;
54}
55
56static int vnet_send_attr(struct vio_driver_state *vio)
57{
58 struct vnet_port *port = to_vnet_port(vio);
59 struct net_device *dev = port->vp->dev;
60 struct vio_net_attr_info pkt;
61 int i;
62
63 memset(&pkt, 0, sizeof(pkt));
64 pkt.tag.type = VIO_TYPE_CTRL;
65 pkt.tag.stype = VIO_SUBTYPE_INFO;
66 pkt.tag.stype_env = VIO_ATTR_INFO;
67 pkt.tag.sid = vio_send_sid(vio);
68 pkt.xfer_mode = VIO_DRING_MODE;
69 pkt.addr_type = VNET_ADDR_ETHERMAC;
70 pkt.ack_freq = 0;
71 for (i = 0; i < 6; i++)
72 pkt.addr |= (u64)dev->dev_addr[i] << ((5 - i) * 8);
73 pkt.mtu = ETH_FRAME_LEN;
74
75 viodbg(HS, "SEND NET ATTR xmode[0x%x] atype[0x%x] addr[%llx] "
76 "ackfreq[%u] mtu[%llu]\n",
77 pkt.xfer_mode, pkt.addr_type,
78 (unsigned long long) pkt.addr,
79 pkt.ack_freq,
80 (unsigned long long) pkt.mtu);
81
82 return vio_ldc_send(vio, &pkt, sizeof(pkt));
83}
84
85static int handle_attr_info(struct vio_driver_state *vio,
86 struct vio_net_attr_info *pkt)
87{
88 viodbg(HS, "GOT NET ATTR INFO xmode[0x%x] atype[0x%x] addr[%llx] "
89 "ackfreq[%u] mtu[%llu]\n",
90 pkt->xfer_mode, pkt->addr_type,
91 (unsigned long long) pkt->addr,
92 pkt->ack_freq,
93 (unsigned long long) pkt->mtu);
94
95 pkt->tag.sid = vio_send_sid(vio);
96
97 if (pkt->xfer_mode != VIO_DRING_MODE ||
98 pkt->addr_type != VNET_ADDR_ETHERMAC ||
99 pkt->mtu != ETH_FRAME_LEN) {
100 viodbg(HS, "SEND NET ATTR NACK\n");
101
102 pkt->tag.stype = VIO_SUBTYPE_NACK;
103
104 (void) vio_ldc_send(vio, pkt, sizeof(*pkt));
105
106 return -ECONNRESET;
107 } else {
108 viodbg(HS, "SEND NET ATTR ACK\n");
109
110 pkt->tag.stype = VIO_SUBTYPE_ACK;
111
112 return vio_ldc_send(vio, pkt, sizeof(*pkt));
113 }
114
115}
116
117static int handle_attr_ack(struct vio_driver_state *vio,
118 struct vio_net_attr_info *pkt)
119{
120 viodbg(HS, "GOT NET ATTR ACK\n");
121
122 return 0;
123}
124
125static int handle_attr_nack(struct vio_driver_state *vio,
126 struct vio_net_attr_info *pkt)
127{
128 viodbg(HS, "GOT NET ATTR NACK\n");
129
130 return -ECONNRESET;
131}
132
133static int vnet_handle_attr(struct vio_driver_state *vio, void *arg)
134{
135 struct vio_net_attr_info *pkt = arg;
136
137 switch (pkt->tag.stype) {
138 case VIO_SUBTYPE_INFO:
139 return handle_attr_info(vio, pkt);
140
141 case VIO_SUBTYPE_ACK:
142 return handle_attr_ack(vio, pkt);
143
144 case VIO_SUBTYPE_NACK:
145 return handle_attr_nack(vio, pkt);
146
147 default:
148 return -ECONNRESET;
149 }
150}
151
152static void vnet_handshake_complete(struct vio_driver_state *vio)
153{
154 struct vio_dring_state *dr;
155
156 dr = &vio->drings[VIO_DRIVER_RX_RING];
157 dr->snd_nxt = dr->rcv_nxt = 1;
158
159 dr = &vio->drings[VIO_DRIVER_TX_RING];
160 dr->snd_nxt = dr->rcv_nxt = 1;
161}
162
163/* The hypervisor interface that implements copying to/from imported
164 * memory from another domain requires that copies are done to 8-byte
165 * aligned buffers, and that the lengths of such copies are also 8-byte
166 * multiples.
167 *
168 * So we align skb->data to an 8-byte multiple and pad-out the data
169 * area so we can round the copy length up to the next multiple of
170 * 8 for the copy.
171 *
172 * The transmitter puts the actual start of the packet 6 bytes into
173 * the buffer it sends over, so that the IP headers after the ethernet
174 * header are aligned properly. These 6 bytes are not in the descriptor
175 * length, they are simply implied. This offset is represented using
176 * the VNET_PACKET_SKIP macro.
177 */
178static struct sk_buff *alloc_and_align_skb(struct net_device *dev,
179 unsigned int len)
180{
181 struct sk_buff *skb = netdev_alloc_skb(dev, len+VNET_PACKET_SKIP+8+8);
182 unsigned long addr, off;
183
184 if (unlikely(!skb))
185 return NULL;
186
187 addr = (unsigned long) skb->data;
188 off = ((addr + 7UL) & ~7UL) - addr;
189 if (off)
190 skb_reserve(skb, off);
191
192 return skb;
193}
194
195static int vnet_rx_one(struct vnet_port *port, unsigned int len,
196 struct ldc_trans_cookie *cookies, int ncookies)
197{
198 struct net_device *dev = port->vp->dev;
199 unsigned int copy_len;
200 struct sk_buff *skb;
201 int err;
202
203 err = -EMSGSIZE;
204 if (unlikely(len < ETH_ZLEN || len > ETH_FRAME_LEN)) {
205 dev->stats.rx_length_errors++;
206 goto out_dropped;
207 }
208
209 skb = alloc_and_align_skb(dev, len);
210 err = -ENOMEM;
211 if (unlikely(!skb)) {
212 dev->stats.rx_missed_errors++;
213 goto out_dropped;
214 }
215
216 copy_len = (len + VNET_PACKET_SKIP + 7U) & ~7U;
217 skb_put(skb, copy_len);
218 err = ldc_copy(port->vio.lp, LDC_COPY_IN,
219 skb->data, copy_len, 0,
220 cookies, ncookies);
221 if (unlikely(err < 0)) {
222 dev->stats.rx_frame_errors++;
223 goto out_free_skb;
224 }
225
226 skb_pull(skb, VNET_PACKET_SKIP);
227 skb_trim(skb, len);
228 skb->protocol = eth_type_trans(skb, dev);
229
230 dev->stats.rx_packets++;
231 dev->stats.rx_bytes += len;
232
233 netif_rx(skb);
234
235 return 0;
236
237out_free_skb:
238 kfree_skb(skb);
239
240out_dropped:
241 dev->stats.rx_dropped++;
242 return err;
243}
244
245static int vnet_send_ack(struct vnet_port *port, struct vio_dring_state *dr,
246 u32 start, u32 end, u8 vio_dring_state)
247{
248 struct vio_dring_data hdr = {
249 .tag = {
250 .type = VIO_TYPE_DATA,
251 .stype = VIO_SUBTYPE_ACK,
252 .stype_env = VIO_DRING_DATA,
253 .sid = vio_send_sid(&port->vio),
254 },
255 .dring_ident = dr->ident,
256 .start_idx = start,
257 .end_idx = end,
258 .state = vio_dring_state,
259 };
260 int err, delay;
261
262 hdr.seq = dr->snd_nxt;
263 delay = 1;
264 do {
265 err = vio_ldc_send(&port->vio, &hdr, sizeof(hdr));
266 if (err > 0) {
267 dr->snd_nxt++;
268 break;
269 }
270 udelay(delay);
271 if ((delay <<= 1) > 128)
272 delay = 128;
273 } while (err == -EAGAIN);
274
275 return err;
276}
277
278static u32 next_idx(u32 idx, struct vio_dring_state *dr)
279{
280 if (++idx == dr->num_entries)
281 idx = 0;
282 return idx;
283}
284
285static u32 prev_idx(u32 idx, struct vio_dring_state *dr)
286{
287 if (idx == 0)
288 idx = dr->num_entries - 1;
289 else
290 idx--;
291
292 return idx;
293}
294
295static struct vio_net_desc *get_rx_desc(struct vnet_port *port,
296 struct vio_dring_state *dr,
297 u32 index)
298{
299 struct vio_net_desc *desc = port->vio.desc_buf;
300 int err;
301
302 err = ldc_get_dring_entry(port->vio.lp, desc, dr->entry_size,
303 (index * dr->entry_size),
304 dr->cookies, dr->ncookies);
305 if (err < 0)
306 return ERR_PTR(err);
307
308 return desc;
309}
310
311static int put_rx_desc(struct vnet_port *port,
312 struct vio_dring_state *dr,
313 struct vio_net_desc *desc,
314 u32 index)
315{
316 int err;
317
318 err = ldc_put_dring_entry(port->vio.lp, desc, dr->entry_size,
319 (index * dr->entry_size),
320 dr->cookies, dr->ncookies);
321 if (err < 0)
322 return err;
323
324 return 0;
325}
326
327static int vnet_walk_rx_one(struct vnet_port *port,
328 struct vio_dring_state *dr,
329 u32 index, int *needs_ack)
330{
331 struct vio_net_desc *desc = get_rx_desc(port, dr, index);
332 struct vio_driver_state *vio = &port->vio;
333 int err;
334
335 if (IS_ERR(desc))
336 return PTR_ERR(desc);
337
338 viodbg(DATA, "vio_walk_rx_one desc[%02x:%02x:%08x:%08x:%lx:%lx]\n",
339 desc->hdr.state, desc->hdr.ack,
340 desc->size, desc->ncookies,
341 desc->cookies[0].cookie_addr,
342 desc->cookies[0].cookie_size);
343
344 if (desc->hdr.state != VIO_DESC_READY)
345 return 1;
346 err = vnet_rx_one(port, desc->size, desc->cookies, desc->ncookies);
347 if (err == -ECONNRESET)
348 return err;
349 desc->hdr.state = VIO_DESC_DONE;
350 err = put_rx_desc(port, dr, desc, index);
351 if (err < 0)
352 return err;
353 *needs_ack = desc->hdr.ack;
354 return 0;
355}
356
357static int vnet_walk_rx(struct vnet_port *port, struct vio_dring_state *dr,
358 u32 start, u32 end)
359{
360 struct vio_driver_state *vio = &port->vio;
361 int ack_start = -1, ack_end = -1;
362
363 end = (end == (u32) -1) ? prev_idx(start, dr) : next_idx(end, dr);
364
365 viodbg(DATA, "vnet_walk_rx start[%08x] end[%08x]\n", start, end);
366
367 while (start != end) {
368 int ack = 0, err = vnet_walk_rx_one(port, dr, start, &ack);
369 if (err == -ECONNRESET)
370 return err;
371 if (err != 0)
372 break;
373 if (ack_start == -1)
374 ack_start = start;
375 ack_end = start;
376 start = next_idx(start, dr);
377 if (ack && start != end) {
378 err = vnet_send_ack(port, dr, ack_start, ack_end,
379 VIO_DRING_ACTIVE);
380 if (err == -ECONNRESET)
381 return err;
382 ack_start = -1;
383 }
384 }
385 if (unlikely(ack_start == -1))
386 ack_start = ack_end = prev_idx(start, dr);
387 return vnet_send_ack(port, dr, ack_start, ack_end, VIO_DRING_STOPPED);
388}
389
390static int vnet_rx(struct vnet_port *port, void *msgbuf)
391{
392 struct vio_dring_data *pkt = msgbuf;
393 struct vio_dring_state *dr = &port->vio.drings[VIO_DRIVER_RX_RING];
394 struct vio_driver_state *vio = &port->vio;
395
396 viodbg(DATA, "vnet_rx stype_env[%04x] seq[%016lx] rcv_nxt[%016lx]\n",
397 pkt->tag.stype_env, pkt->seq, dr->rcv_nxt);
398
399 if (unlikely(pkt->tag.stype_env != VIO_DRING_DATA))
400 return 0;
401 if (unlikely(pkt->seq != dr->rcv_nxt)) {
402 printk(KERN_ERR PFX "RX out of sequence seq[0x%lx] "
403 "rcv_nxt[0x%lx]\n", pkt->seq, dr->rcv_nxt);
404 return 0;
405 }
406
407 dr->rcv_nxt++;
408
409 /* XXX Validate pkt->start_idx and pkt->end_idx XXX */
410
411 return vnet_walk_rx(port, dr, pkt->start_idx, pkt->end_idx);
412}
413
414static int idx_is_pending(struct vio_dring_state *dr, u32 end)
415{
416 u32 idx = dr->cons;
417 int found = 0;
418
419 while (idx != dr->prod) {
420 if (idx == end) {
421 found = 1;
422 break;
423 }
424 idx = next_idx(idx, dr);
425 }
426 return found;
427}
428
429static int vnet_ack(struct vnet_port *port, void *msgbuf)
430{
431 struct vio_dring_state *dr = &port->vio.drings[VIO_DRIVER_TX_RING];
432 struct vio_dring_data *pkt = msgbuf;
433 struct net_device *dev;
434 struct vnet *vp;
435 u32 end;
436
437 if (unlikely(pkt->tag.stype_env != VIO_DRING_DATA))
438 return 0;
439
440 end = pkt->end_idx;
441 if (unlikely(!idx_is_pending(dr, end)))
442 return 0;
443
444 dr->cons = next_idx(end, dr);
445
446 vp = port->vp;
447 dev = vp->dev;
448 if (unlikely(netif_queue_stopped(dev) &&
449 vnet_tx_dring_avail(dr) >= VNET_TX_WAKEUP_THRESH(dr)))
450 return 1;
451
452 return 0;
453}
454
455static int vnet_nack(struct vnet_port *port, void *msgbuf)
456{
457 /* XXX just reset or similar XXX */
458 return 0;
459}
460
461static void maybe_tx_wakeup(struct vnet *vp)
462{
463 struct net_device *dev = vp->dev;
464
465 netif_tx_lock(dev);
466 if (likely(netif_queue_stopped(dev))) {
467 struct vnet_port *port;
468 int wake = 1;
469
470 list_for_each_entry(port, &vp->port_list, list) {
471 struct vio_dring_state *dr;
472
473 dr = &port->vio.drings[VIO_DRIVER_TX_RING];
474 if (vnet_tx_dring_avail(dr) <
475 VNET_TX_WAKEUP_THRESH(dr)) {
476 wake = 0;
477 break;
478 }
479 }
480 if (wake)
481 netif_wake_queue(dev);
482 }
483 netif_tx_unlock(dev);
484}
485
486static void vnet_event(void *arg, int event)
487{
488 struct vnet_port *port = arg;
489 struct vio_driver_state *vio = &port->vio;
490 unsigned long flags;
491 int tx_wakeup, err;
492
493 spin_lock_irqsave(&vio->lock, flags);
494
495 if (unlikely(event == LDC_EVENT_RESET ||
496 event == LDC_EVENT_UP)) {
497 vio_link_state_change(vio, event);
498 spin_unlock_irqrestore(&vio->lock, flags);
499
500 return;
501 }
502
503 if (unlikely(event != LDC_EVENT_DATA_READY)) {
504 printk(KERN_WARNING PFX "Unexpected LDC event %d\n", event);
505 spin_unlock_irqrestore(&vio->lock, flags);
506 return;
507 }
508
509 tx_wakeup = err = 0;
510 while (1) {
511 union {
512 struct vio_msg_tag tag;
513 u64 raw[8];
514 } msgbuf;
515
516 err = ldc_read(vio->lp, &msgbuf, sizeof(msgbuf));
517 if (unlikely(err < 0)) {
518 if (err == -ECONNRESET)
519 vio_conn_reset(vio);
520 break;
521 }
522 if (err == 0)
523 break;
524 viodbg(DATA, "TAG [%02x:%02x:%04x:%08x]\n",
525 msgbuf.tag.type,
526 msgbuf.tag.stype,
527 msgbuf.tag.stype_env,
528 msgbuf.tag.sid);
529 err = vio_validate_sid(vio, &msgbuf.tag);
530 if (err < 0)
531 break;
532
533 if (likely(msgbuf.tag.type == VIO_TYPE_DATA)) {
534 if (msgbuf.tag.stype == VIO_SUBTYPE_INFO) {
535 err = vnet_rx(port, &msgbuf);
536 } else if (msgbuf.tag.stype == VIO_SUBTYPE_ACK) {
537 err = vnet_ack(port, &msgbuf);
538 if (err > 0)
539 tx_wakeup |= err;
540 } else if (msgbuf.tag.stype == VIO_SUBTYPE_NACK) {
541 err = vnet_nack(port, &msgbuf);
542 }
543 } else if (msgbuf.tag.type == VIO_TYPE_CTRL) {
544 err = vio_control_pkt_engine(vio, &msgbuf);
545 if (err)
546 break;
547 } else {
548 err = vnet_handle_unknown(port, &msgbuf);
549 }
550 if (err == -ECONNRESET)
551 break;
552 }
553 spin_unlock(&vio->lock);
554 if (unlikely(tx_wakeup && err != -ECONNRESET))
555 maybe_tx_wakeup(port->vp);
556 local_irq_restore(flags);
557}
558
559static int __vnet_tx_trigger(struct vnet_port *port)
560{
561 struct vio_dring_state *dr = &port->vio.drings[VIO_DRIVER_TX_RING];
562 struct vio_dring_data hdr = {
563 .tag = {
564 .type = VIO_TYPE_DATA,
565 .stype = VIO_SUBTYPE_INFO,
566 .stype_env = VIO_DRING_DATA,
567 .sid = vio_send_sid(&port->vio),
568 },
569 .dring_ident = dr->ident,
570 .start_idx = dr->prod,
571 .end_idx = (u32) -1,
572 };
573 int err, delay;
574
575 hdr.seq = dr->snd_nxt;
576 delay = 1;
577 do {
578 err = vio_ldc_send(&port->vio, &hdr, sizeof(hdr));
579 if (err > 0) {
580 dr->snd_nxt++;
581 break;
582 }
583 udelay(delay);
584 if ((delay <<= 1) > 128)
585 delay = 128;
586 } while (err == -EAGAIN);
587
588 return err;
589}
590
591struct vnet_port *__tx_port_find(struct vnet *vp, struct sk_buff *skb)
592{
593 unsigned int hash = vnet_hashfn(skb->data);
594 struct hlist_head *hp = &vp->port_hash[hash];
595 struct hlist_node *n;
596 struct vnet_port *port;
597
598 hlist_for_each_entry(port, n, hp, hash) {
599 if (!compare_ether_addr(port->raddr, skb->data))
600 return port;
601 }
602 port = NULL;
603 if (!list_empty(&vp->port_list))
604 port = list_entry(vp->port_list.next, struct vnet_port, list);
605
606 return port;
607}
608
609struct vnet_port *tx_port_find(struct vnet *vp, struct sk_buff *skb)
610{
611 struct vnet_port *ret;
612 unsigned long flags;
613
614 spin_lock_irqsave(&vp->lock, flags);
615 ret = __tx_port_find(vp, skb);
616 spin_unlock_irqrestore(&vp->lock, flags);
617
618 return ret;
619}
620
621static int vnet_start_xmit(struct sk_buff *skb, struct net_device *dev)
622{
623 struct vnet *vp = netdev_priv(dev);
624 struct vnet_port *port = tx_port_find(vp, skb);
625 struct vio_dring_state *dr;
626 struct vio_net_desc *d;
627 unsigned long flags;
628 unsigned int len;
629 void *tx_buf;
630 int i, err;
631
632 if (unlikely(!port))
633 goto out_dropped;
634
635 spin_lock_irqsave(&port->vio.lock, flags);
636
637 dr = &port->vio.drings[VIO_DRIVER_TX_RING];
638 if (unlikely(vnet_tx_dring_avail(dr) < 2)) {
639 if (!netif_queue_stopped(dev)) {
640 netif_stop_queue(dev);
641
642 /* This is a hard error, log it. */
643 printk(KERN_ERR PFX "%s: BUG! Tx Ring full when "
644 "queue awake!\n", dev->name);
645 dev->stats.tx_errors++;
646 }
647 spin_unlock_irqrestore(&port->vio.lock, flags);
648 return NETDEV_TX_BUSY;
649 }
650
651 d = vio_dring_cur(dr);
652
653 tx_buf = port->tx_bufs[dr->prod].buf;
654 skb_copy_from_linear_data(skb, tx_buf + VNET_PACKET_SKIP, skb->len);
655
656 len = skb->len;
657 if (len < ETH_ZLEN) {
658 len = ETH_ZLEN;
659 memset(tx_buf+VNET_PACKET_SKIP+skb->len, 0, len - skb->len);
660 }
661
662 d->hdr.ack = VIO_ACK_ENABLE;
663 d->size = len;
664 d->ncookies = port->tx_bufs[dr->prod].ncookies;
665 for (i = 0; i < d->ncookies; i++)
666 d->cookies[i] = port->tx_bufs[dr->prod].cookies[i];
667
668 /* This has to be a non-SMP write barrier because we are writing
669 * to memory which is shared with the peer LDOM.
670 */
671 wmb();
672
673 d->hdr.state = VIO_DESC_READY;
674
675 err = __vnet_tx_trigger(port);
676 if (unlikely(err < 0)) {
677 printk(KERN_INFO PFX "%s: TX trigger error %d\n",
678 dev->name, err);
679 d->hdr.state = VIO_DESC_FREE;
680 dev->stats.tx_carrier_errors++;
681 goto out_dropped_unlock;
682 }
683
684 dev->stats.tx_packets++;
685 dev->stats.tx_bytes += skb->len;
686
687 dr->prod = (dr->prod + 1) & (VNET_TX_RING_SIZE - 1);
688 if (unlikely(vnet_tx_dring_avail(dr) < 2)) {
689 netif_stop_queue(dev);
690 if (vnet_tx_dring_avail(dr) > VNET_TX_WAKEUP_THRESH(dr))
691 netif_wake_queue(dev);
692 }
693
694 spin_unlock_irqrestore(&port->vio.lock, flags);
695
696 dev_kfree_skb(skb);
697
698 dev->trans_start = jiffies;
699 return NETDEV_TX_OK;
700
701out_dropped_unlock:
702 spin_unlock_irqrestore(&port->vio.lock, flags);
703
704out_dropped:
705 dev_kfree_skb(skb);
706 dev->stats.tx_dropped++;
707 return NETDEV_TX_OK;
708}
709
710static void vnet_tx_timeout(struct net_device *dev)
711{
712 /* XXX Implement me XXX */
713}
714
715static int vnet_open(struct net_device *dev)
716{
717 netif_carrier_on(dev);
718 netif_start_queue(dev);
719
720 return 0;
721}
722
723static int vnet_close(struct net_device *dev)
724{
725 netif_stop_queue(dev);
726 netif_carrier_off(dev);
727
728 return 0;
729}
730
731static void vnet_set_rx_mode(struct net_device *dev)
732{
733 /* XXX Implement multicast support XXX */
734}
735
736static int vnet_change_mtu(struct net_device *dev, int new_mtu)
737{
738 if (new_mtu != ETH_DATA_LEN)
739 return -EINVAL;
740
741 dev->mtu = new_mtu;
742 return 0;
743}
744
745static int vnet_set_mac_addr(struct net_device *dev, void *p)
746{
747 return -EINVAL;
748}
749
750static void vnet_get_drvinfo(struct net_device *dev,
751 struct ethtool_drvinfo *info)
752{
753 strcpy(info->driver, DRV_MODULE_NAME);
754 strcpy(info->version, DRV_MODULE_VERSION);
755}
756
757static u32 vnet_get_msglevel(struct net_device *dev)
758{
759 struct vnet *vp = netdev_priv(dev);
760 return vp->msg_enable;
761}
762
763static void vnet_set_msglevel(struct net_device *dev, u32 value)
764{
765 struct vnet *vp = netdev_priv(dev);
766 vp->msg_enable = value;
767}
768
769static const struct ethtool_ops vnet_ethtool_ops = {
770 .get_drvinfo = vnet_get_drvinfo,
771 .get_msglevel = vnet_get_msglevel,
772 .set_msglevel = vnet_set_msglevel,
773 .get_link = ethtool_op_get_link,
774 .get_perm_addr = ethtool_op_get_perm_addr,
775};
776
777static void vnet_port_free_tx_bufs(struct vnet_port *port)
778{
779 struct vio_dring_state *dr;
780 int i;
781
782 dr = &port->vio.drings[VIO_DRIVER_TX_RING];
783 if (dr->base) {
784 ldc_free_exp_dring(port->vio.lp, dr->base,
785 (dr->entry_size * dr->num_entries),
786 dr->cookies, dr->ncookies);
787 dr->base = NULL;
788 dr->entry_size = 0;
789 dr->num_entries = 0;
790 dr->pending = 0;
791 dr->ncookies = 0;
792 }
793
794 for (i = 0; i < VNET_TX_RING_SIZE; i++) {
795 void *buf = port->tx_bufs[i].buf;
796
797 if (!buf)
798 continue;
799
800 ldc_unmap(port->vio.lp,
801 port->tx_bufs[i].cookies,
802 port->tx_bufs[i].ncookies);
803
804 kfree(buf);
805 port->tx_bufs[i].buf = NULL;
806 }
807}
808
809static int __devinit vnet_port_alloc_tx_bufs(struct vnet_port *port)
810{
811 struct vio_dring_state *dr;
812 unsigned long len;
813 int i, err, ncookies;
814 void *dring;
815
816 for (i = 0; i < VNET_TX_RING_SIZE; i++) {
817 void *buf = kzalloc(ETH_FRAME_LEN + 8, GFP_KERNEL);
818 int map_len = (ETH_FRAME_LEN + 7) & ~7;
819
820 err = -ENOMEM;
821 if (!buf) {
822 printk(KERN_ERR "TX buffer allocation failure\n");
823 goto err_out;
824 }
825 err = -EFAULT;
826 if ((unsigned long)buf & (8UL - 1)) {
827 printk(KERN_ERR "TX buffer misaligned\n");
828 kfree(buf);
829 goto err_out;
830 }
831
832 err = ldc_map_single(port->vio.lp, buf, map_len,
833 port->tx_bufs[i].cookies, 2,
834 (LDC_MAP_SHADOW |
835 LDC_MAP_DIRECT |
836 LDC_MAP_RW));
837 if (err < 0) {
838 kfree(buf);
839 goto err_out;
840 }
841 port->tx_bufs[i].buf = buf;
842 port->tx_bufs[i].ncookies = err;
843 }
844
845 dr = &port->vio.drings[VIO_DRIVER_TX_RING];
846
847 len = (VNET_TX_RING_SIZE *
848 (sizeof(struct vio_net_desc) +
849 (sizeof(struct ldc_trans_cookie) * 2)));
850
851 ncookies = VIO_MAX_RING_COOKIES;
852 dring = ldc_alloc_exp_dring(port->vio.lp, len,
853 dr->cookies, &ncookies,
854 (LDC_MAP_SHADOW |
855 LDC_MAP_DIRECT |
856 LDC_MAP_RW));
857 if (IS_ERR(dring)) {
858 err = PTR_ERR(dring);
859 goto err_out;
860 }
861
862 dr->base = dring;
863 dr->entry_size = (sizeof(struct vio_net_desc) +
864 (sizeof(struct ldc_trans_cookie) * 2));
865 dr->num_entries = VNET_TX_RING_SIZE;
866 dr->prod = dr->cons = 0;
867 dr->pending = VNET_TX_RING_SIZE;
868 dr->ncookies = ncookies;
869
870 return 0;
871
872err_out:
873 vnet_port_free_tx_bufs(port);
874
875 return err;
876}
877
878static struct ldc_channel_config vnet_ldc_cfg = {
879 .event = vnet_event,
880 .mtu = 64,
881 .mode = LDC_MODE_UNRELIABLE,
882};
883
884static struct vio_driver_ops vnet_vio_ops = {
885 .send_attr = vnet_send_attr,
886 .handle_attr = vnet_handle_attr,
887 .handshake_complete = vnet_handshake_complete,
888};
889
890const char *remote_macaddr_prop = "remote-mac-address";
891
892static int __devinit vnet_port_probe(struct vio_dev *vdev,
893 const struct vio_device_id *id)
894{
895 struct mdesc_handle *hp;
896 struct vnet_port *port;
897 unsigned long flags;
898 struct vnet *vp;
899 const u64 *rmac;
900 int len, i, err, switch_port;
901
902 vp = dev_get_drvdata(vdev->dev.parent);
903 if (!vp) {
904 printk(KERN_ERR PFX "Cannot find port parent vnet.\n");
905 return -ENODEV;
906 }
907
908 hp = mdesc_grab();
909
910 rmac = mdesc_get_property(hp, vdev->mp, remote_macaddr_prop, &len);
911 err = -ENODEV;
912 if (!rmac) {
913 printk(KERN_ERR PFX "Port lacks %s property.\n",
914 remote_macaddr_prop);
915 goto err_out_put_mdesc;
916 }
917
918 port = kzalloc(sizeof(*port), GFP_KERNEL);
919 err = -ENOMEM;
920 if (!port) {
921 printk(KERN_ERR PFX "Cannot allocate vnet_port.\n");
922 goto err_out_put_mdesc;
923 }
924
925 for (i = 0; i < ETH_ALEN; i++)
926 port->raddr[i] = (*rmac >> (5 - i) * 8) & 0xff;
927
928 port->vp = vp;
929
930 err = vio_driver_init(&port->vio, vdev, VDEV_NETWORK,
931 vnet_versions, ARRAY_SIZE(vnet_versions),
932 &vnet_vio_ops, vp->dev->name);
933 if (err)
934 goto err_out_free_port;
935
936 err = vio_ldc_alloc(&port->vio, &vnet_ldc_cfg, port);
937 if (err)
938 goto err_out_free_port;
939
940 err = vnet_port_alloc_tx_bufs(port);
941 if (err)
942 goto err_out_free_ldc;
943
944 INIT_HLIST_NODE(&port->hash);
945 INIT_LIST_HEAD(&port->list);
946
947 switch_port = 0;
948 if (mdesc_get_property(hp, vdev->mp, "switch-port", NULL) != NULL)
949 switch_port = 1;
950
951 spin_lock_irqsave(&vp->lock, flags);
952 if (switch_port)
953 list_add(&port->list, &vp->port_list);
954 else
955 list_add_tail(&port->list, &vp->port_list);
956 hlist_add_head(&port->hash, &vp->port_hash[vnet_hashfn(port->raddr)]);
957 spin_unlock_irqrestore(&vp->lock, flags);
958
959 dev_set_drvdata(&vdev->dev, port);
960
961 printk(KERN_INFO "%s: PORT ( remote-mac ", vp->dev->name);
962 for (i = 0; i < 6; i++)
963 printk("%2.2x%c", port->raddr[i], i == 5 ? ' ' : ':');
964 if (switch_port)
965 printk("switch-port ");
966 printk(")\n");
967
968 vio_port_up(&port->vio);
969
970 mdesc_release(hp);
971
972 return 0;
973
974err_out_free_ldc:
975 vio_ldc_free(&port->vio);
976
977err_out_free_port:
978 kfree(port);
979
980err_out_put_mdesc:
981 mdesc_release(hp);
982 return err;
983}
984
985static int vnet_port_remove(struct vio_dev *vdev)
986{
987 struct vnet_port *port = dev_get_drvdata(&vdev->dev);
988
989 if (port) {
990 struct vnet *vp = port->vp;
991 unsigned long flags;
992
993 del_timer_sync(&port->vio.timer);
994
995 spin_lock_irqsave(&vp->lock, flags);
996 list_del(&port->list);
997 hlist_del(&port->hash);
998 spin_unlock_irqrestore(&vp->lock, flags);
999
1000 vnet_port_free_tx_bufs(port);
1001 vio_ldc_free(&port->vio);
1002
1003 dev_set_drvdata(&vdev->dev, NULL);
1004
1005 kfree(port);
1006 }
1007 return 0;
1008}
1009
1010static struct vio_device_id vnet_port_match[] = {
1011 {
1012 .type = "vnet-port",
1013 },
1014 {},
1015};
1016MODULE_DEVICE_TABLE(vio, vnet_match);
1017
1018static struct vio_driver vnet_port_driver = {
1019 .id_table = vnet_port_match,
1020 .probe = vnet_port_probe,
1021 .remove = vnet_port_remove,
1022 .driver = {
1023 .name = "vnet_port",
1024 .owner = THIS_MODULE,
1025 }
1026};
1027
1028const char *local_mac_prop = "local-mac-address";
1029
1030static int __devinit vnet_probe(struct vio_dev *vdev,
1031 const struct vio_device_id *id)
1032{
1033 static int vnet_version_printed;
1034 struct mdesc_handle *hp;
1035 struct net_device *dev;
1036 struct vnet *vp;
1037 const u64 *mac;
1038 int err, i, len;
1039
1040 if (vnet_version_printed++ == 0)
1041 printk(KERN_INFO "%s", version);
1042
1043 hp = mdesc_grab();
1044
1045 mac = mdesc_get_property(hp, vdev->mp, local_mac_prop, &len);
1046 if (!mac) {
1047 printk(KERN_ERR PFX "vnet lacks %s property.\n",
1048 local_mac_prop);
1049 err = -ENODEV;
1050 goto err_out;
1051 }
1052
1053 dev = alloc_etherdev(sizeof(*vp));
1054 if (!dev) {
1055 printk(KERN_ERR PFX "Etherdev alloc failed, aborting.\n");
1056 err = -ENOMEM;
1057 goto err_out;
1058 }
1059
1060 for (i = 0; i < ETH_ALEN; i++)
1061 dev->dev_addr[i] = (*mac >> (5 - i) * 8) & 0xff;
1062
1063 memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
1064
1065 SET_NETDEV_DEV(dev, &vdev->dev);
1066
1067 vp = netdev_priv(dev);
1068
1069 spin_lock_init(&vp->lock);
1070 vp->dev = dev;
1071 vp->vdev = vdev;
1072
1073 INIT_LIST_HEAD(&vp->port_list);
1074 for (i = 0; i < VNET_PORT_HASH_SIZE; i++)
1075 INIT_HLIST_HEAD(&vp->port_hash[i]);
1076
1077 dev->open = vnet_open;
1078 dev->stop = vnet_close;
1079 dev->set_multicast_list = vnet_set_rx_mode;
1080 dev->set_mac_address = vnet_set_mac_addr;
1081 dev->tx_timeout = vnet_tx_timeout;
1082 dev->ethtool_ops = &vnet_ethtool_ops;
1083 dev->watchdog_timeo = VNET_TX_TIMEOUT;
1084 dev->change_mtu = vnet_change_mtu;
1085 dev->hard_start_xmit = vnet_start_xmit;
1086
1087 err = register_netdev(dev);
1088 if (err) {
1089 printk(KERN_ERR PFX "Cannot register net device, "
1090 "aborting.\n");
1091 goto err_out_free_dev;
1092 }
1093
1094 printk(KERN_INFO "%s: Sun LDOM vnet ", dev->name);
1095
1096 for (i = 0; i < 6; i++)
1097 printk("%2.2x%c", dev->dev_addr[i], i == 5 ? '\n' : ':');
1098
1099 dev_set_drvdata(&vdev->dev, vp);
1100
1101 mdesc_release(hp);
1102
1103 return 0;
1104
1105err_out_free_dev:
1106 free_netdev(dev);
1107
1108err_out:
1109 mdesc_release(hp);
1110 return err;
1111}
1112
1113static int vnet_remove(struct vio_dev *vdev)
1114{
1115
1116 struct vnet *vp = dev_get_drvdata(&vdev->dev);
1117
1118 if (vp) {
1119 /* XXX unregister port, or at least check XXX */
1120 unregister_netdevice(vp->dev);
1121 dev_set_drvdata(&vdev->dev, NULL);
1122 }
1123 return 0;
1124}
1125
1126static struct vio_device_id vnet_match[] = {
1127 {
1128 .type = "network",
1129 },
1130 {},
1131};
1132MODULE_DEVICE_TABLE(vio, vnet_match);
1133
1134static struct vio_driver vnet_driver = {
1135 .id_table = vnet_match,
1136 .probe = vnet_probe,
1137 .remove = vnet_remove,
1138 .driver = {
1139 .name = "vnet",
1140 .owner = THIS_MODULE,
1141 }
1142};
1143
1144static int __init vnet_init(void)
1145{
1146 int err = vio_register_driver(&vnet_driver);
1147
1148 if (!err) {
1149 err = vio_register_driver(&vnet_port_driver);
1150 if (err)
1151 vio_unregister_driver(&vnet_driver);
1152 }
1153
1154 return err;
1155}
1156
1157static void __exit vnet_exit(void)
1158{
1159 vio_unregister_driver(&vnet_port_driver);
1160 vio_unregister_driver(&vnet_driver);
1161}
1162
1163module_init(vnet_init);
1164module_exit(vnet_exit);
diff --git a/drivers/net/sunvnet.h b/drivers/net/sunvnet.h
new file mode 100644
index 000000000000..1c887302d46d
--- /dev/null
+++ b/drivers/net/sunvnet.h
@@ -0,0 +1,70 @@
1#ifndef _SUNVNET_H
2#define _SUNVNET_H
3
4#define DESC_NCOOKIES(entry_size) \
5 ((entry_size) - sizeof(struct vio_net_desc))
6
7/* length of time before we decide the hardware is borked,
8 * and dev->tx_timeout() should be called to fix the problem
9 */
10#define VNET_TX_TIMEOUT (5 * HZ)
11
12#define VNET_TX_RING_SIZE 512
13#define VNET_TX_WAKEUP_THRESH(dr) ((dr)->pending / 4)
14
15/* VNET packets are sent in buffers with the first 6 bytes skipped
16 * so that after the ethernet header the IPv4/IPv6 headers are aligned
17 * properly.
18 */
19#define VNET_PACKET_SKIP 6
20
21struct vnet_tx_entry {
22 void *buf;
23 unsigned int ncookies;
24 struct ldc_trans_cookie cookies[2];
25};
26
27struct vnet;
28struct vnet_port {
29 struct vio_driver_state vio;
30
31 struct hlist_node hash;
32 u8 raddr[ETH_ALEN];
33
34 struct vnet *vp;
35
36 struct vnet_tx_entry tx_bufs[VNET_TX_RING_SIZE];
37
38 struct list_head list;
39};
40
41static inline struct vnet_port *to_vnet_port(struct vio_driver_state *vio)
42{
43 return container_of(vio, struct vnet_port, vio);
44}
45
46#define VNET_PORT_HASH_SIZE 16
47#define VNET_PORT_HASH_MASK (VNET_PORT_HASH_SIZE - 1)
48
49static inline unsigned int vnet_hashfn(u8 *mac)
50{
51 unsigned int val = mac[4] ^ mac[5];
52
53 return val & (VNET_PORT_HASH_MASK);
54}
55
56struct vnet {
57 /* Protects port_list and port_hash. */
58 spinlock_t lock;
59
60 struct net_device *dev;
61
62 u32 msg_enable;
63 struct vio_dev *vdev;
64
65 struct list_head port_list;
66
67 struct hlist_head port_hash[VNET_PORT_HASH_SIZE];
68};
69
70#endif /* _SUNVNET_H */
diff --git a/drivers/serial/sunhv.c b/drivers/serial/sunhv.c
index 96557e6dba60..17bcca53d6a1 100644
--- a/drivers/serial/sunhv.c
+++ b/drivers/serial/sunhv.c
@@ -440,8 +440,16 @@ static void sunhv_console_write_paged(struct console *con, const char *s, unsign
440{ 440{
441 struct uart_port *port = sunhv_port; 441 struct uart_port *port = sunhv_port;
442 unsigned long flags; 442 unsigned long flags;
443 int locked = 1;
444
445 local_irq_save(flags);
446 if (port->sysrq) {
447 locked = 0;
448 } else if (oops_in_progress) {
449 locked = spin_trylock(&port->lock);
450 } else
451 spin_lock(&port->lock);
443 452
444 spin_lock_irqsave(&port->lock, flags);
445 while (n > 0) { 453 while (n > 0) {
446 unsigned long ra = __pa(con_write_page); 454 unsigned long ra = __pa(con_write_page);
447 unsigned long page_bytes; 455 unsigned long page_bytes;
@@ -469,7 +477,10 @@ static void sunhv_console_write_paged(struct console *con, const char *s, unsign
469 ra += written; 477 ra += written;
470 } 478 }
471 } 479 }
472 spin_unlock_irqrestore(&port->lock, flags); 480
481 if (locked)
482 spin_unlock(&port->lock);
483 local_irq_restore(flags);
473} 484}
474 485
475static inline void sunhv_console_putchar(struct uart_port *port, char c) 486static inline void sunhv_console_putchar(struct uart_port *port, char c)
@@ -488,7 +499,15 @@ static void sunhv_console_write_bychar(struct console *con, const char *s, unsig
488{ 499{
489 struct uart_port *port = sunhv_port; 500 struct uart_port *port = sunhv_port;
490 unsigned long flags; 501 unsigned long flags;
491 int i; 502 int i, locked = 1;
503
504 local_irq_save(flags);
505 if (port->sysrq) {
506 locked = 0;
507 } else if (oops_in_progress) {
508 locked = spin_trylock(&port->lock);
509 } else
510 spin_lock(&port->lock);
492 511
493 spin_lock_irqsave(&port->lock, flags); 512 spin_lock_irqsave(&port->lock, flags);
494 for (i = 0; i < n; i++) { 513 for (i = 0; i < n; i++) {
@@ -496,7 +515,10 @@ static void sunhv_console_write_bychar(struct console *con, const char *s, unsig
496 sunhv_console_putchar(port, '\r'); 515 sunhv_console_putchar(port, '\r');
497 sunhv_console_putchar(port, *s++); 516 sunhv_console_putchar(port, *s++);
498 } 517 }
499 spin_unlock_irqrestore(&port->lock, flags); 518
519 if (locked)
520 spin_unlock(&port->lock);
521 local_irq_restore(flags);
500} 522}
501 523
502static struct console sunhv_console = { 524static struct console sunhv_console = {
diff --git a/drivers/serial/sunsab.c b/drivers/serial/sunsab.c
index deb9ab4b5a0b..8a0f9e4408d4 100644
--- a/drivers/serial/sunsab.c
+++ b/drivers/serial/sunsab.c
@@ -860,22 +860,31 @@ static int num_channels;
860static void sunsab_console_putchar(struct uart_port *port, int c) 860static void sunsab_console_putchar(struct uart_port *port, int c)
861{ 861{
862 struct uart_sunsab_port *up = (struct uart_sunsab_port *)port; 862 struct uart_sunsab_port *up = (struct uart_sunsab_port *)port;
863 unsigned long flags;
864
865 spin_lock_irqsave(&up->port.lock, flags);
866 863
867 sunsab_tec_wait(up); 864 sunsab_tec_wait(up);
868 writeb(c, &up->regs->w.tic); 865 writeb(c, &up->regs->w.tic);
869
870 spin_unlock_irqrestore(&up->port.lock, flags);
871} 866}
872 867
873static void sunsab_console_write(struct console *con, const char *s, unsigned n) 868static void sunsab_console_write(struct console *con, const char *s, unsigned n)
874{ 869{
875 struct uart_sunsab_port *up = &sunsab_ports[con->index]; 870 struct uart_sunsab_port *up = &sunsab_ports[con->index];
871 unsigned long flags;
872 int locked = 1;
873
874 local_irq_save(flags);
875 if (up->port.sysrq) {
876 locked = 0;
877 } else if (oops_in_progress) {
878 locked = spin_trylock(&up->port.lock);
879 } else
880 spin_lock(&up->port.lock);
876 881
877 uart_console_write(&up->port, s, n, sunsab_console_putchar); 882 uart_console_write(&up->port, s, n, sunsab_console_putchar);
878 sunsab_tec_wait(up); 883 sunsab_tec_wait(up);
884
885 if (locked)
886 spin_unlock(&up->port.lock);
887 local_irq_restore(flags);
879} 888}
880 889
881static int sunsab_console_setup(struct console *con, char *options) 890static int sunsab_console_setup(struct console *con, char *options)
diff --git a/drivers/serial/sunsu.c b/drivers/serial/sunsu.c
index 2a63cdba3208..26d720baf88c 100644
--- a/drivers/serial/sunsu.c
+++ b/drivers/serial/sunsu.c
@@ -1288,7 +1288,17 @@ static void sunsu_console_write(struct console *co, const char *s,
1288 unsigned int count) 1288 unsigned int count)
1289{ 1289{
1290 struct uart_sunsu_port *up = &sunsu_ports[co->index]; 1290 struct uart_sunsu_port *up = &sunsu_ports[co->index];
1291 unsigned long flags;
1291 unsigned int ier; 1292 unsigned int ier;
1293 int locked = 1;
1294
1295 local_irq_save(flags);
1296 if (up->port.sysrq) {
1297 locked = 0;
1298 } else if (oops_in_progress) {
1299 locked = spin_trylock(&up->port.lock);
1300 } else
1301 spin_lock(&up->port.lock);
1292 1302
1293 /* 1303 /*
1294 * First save the UER then disable the interrupts 1304 * First save the UER then disable the interrupts
@@ -1304,6 +1314,10 @@ static void sunsu_console_write(struct console *co, const char *s,
1304 */ 1314 */
1305 wait_for_xmitr(up); 1315 wait_for_xmitr(up);
1306 serial_out(up, UART_IER, ier); 1316 serial_out(up, UART_IER, ier);
1317
1318 if (locked)
1319 spin_unlock(&up->port.lock);
1320 local_irq_restore(flags);
1307} 1321}
1308 1322
1309/* 1323/*
diff --git a/drivers/serial/sunzilog.c b/drivers/serial/sunzilog.c
index 15b6e1cb040b..0a3e10a4a35d 100644
--- a/drivers/serial/sunzilog.c
+++ b/drivers/serial/sunzilog.c
@@ -9,7 +9,7 @@
9 * C. Dost, Pete Zaitcev, Ted Ts'o and Alex Buell for their 9 * C. Dost, Pete Zaitcev, Ted Ts'o and Alex Buell for their
10 * work there. 10 * work there.
11 * 11 *
12 * Copyright (C) 2002, 2006 David S. Miller (davem@davemloft.net) 12 * Copyright (C) 2002, 2006, 2007 David S. Miller (davem@davemloft.net)
13 */ 13 */
14 14
15#include <linux/module.h> 15#include <linux/module.h>
@@ -1151,11 +1151,22 @@ sunzilog_console_write(struct console *con, const char *s, unsigned int count)
1151{ 1151{
1152 struct uart_sunzilog_port *up = &sunzilog_port_table[con->index]; 1152 struct uart_sunzilog_port *up = &sunzilog_port_table[con->index];
1153 unsigned long flags; 1153 unsigned long flags;
1154 int locked = 1;
1155
1156 local_irq_save(flags);
1157 if (up->port.sysrq) {
1158 locked = 0;
1159 } else if (oops_in_progress) {
1160 locked = spin_trylock(&up->port.lock);
1161 } else
1162 spin_lock(&up->port.lock);
1154 1163
1155 spin_lock_irqsave(&up->port.lock, flags);
1156 uart_console_write(&up->port, s, count, sunzilog_putchar); 1164 uart_console_write(&up->port, s, count, sunzilog_putchar);
1157 udelay(2); 1165 udelay(2);
1158 spin_unlock_irqrestore(&up->port.lock, flags); 1166
1167 if (locked)
1168 spin_unlock(&up->port.lock);
1169 local_irq_restore(flags);
1159} 1170}
1160 1171
1161static int __init sunzilog_console_setup(struct console *con, char *options) 1172static int __init sunzilog_console_setup(struct console *con, char *options)