Commit e6ee512f5a77553a6fe08cad68b75d5fdfd2ffb8

Authored by Maciej W. Rozycki
Committed by Linus Torvalds
1 parent f5519caad5

dz.c: Resource management

This is a set of changes to implement proper resource management in the
driver, including iomem space reservation and operating on physical
addresses ioremap()ped appropriately using accessory functions rather than
unportable direct assignments.

Some adjustments to code are made to reflect the architecture of the
interface, which is a centrally controlled multiport (or, as referred to
from DEC documentation, a serial line multiplexer, going up to 8 lines
originally) rather than a bundle of separate ports.

Types are changed, where applicable, to specify the width of hardware
registers explicitly.  The interrupt handler is now managed in the
->startup() and ->shutdown() calls for consistency with other drivers and
also in preparation to handle the handover from the initial firmware-based
console gracefully.

Signed-off-by: Maciej W. Rozycki <macro@linux-mips.org>
Cc: Ralf Baechle <ralf@linux-mips.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

Showing 1 changed file with 188 additions and 101 deletions Side-by-side Diff

... ... @@ -39,6 +39,7 @@
39 39 #include <linux/errno.h>
40 40 #include <linux/init.h>
41 41 #include <linux/interrupt.h>
  42 +#include <linux/ioport.h>
42 43 #include <linux/kernel.h>
43 44 #include <linux/major.h>
44 45 #include <linux/module.h>
45 46  
... ... @@ -47,7 +48,9 @@
47 48 #include <linux/sysrq.h>
48 49 #include <linux/tty.h>
49 50  
  51 +#include <asm/atomic.h>
50 52 #include <asm/bootinfo.h>
  53 +#include <asm/io.h>
51 54 #include <asm/system.h>
52 55  
53 56 #include <asm/dec/interrupts.h>
54 57  
55 58  
56 59  
57 60  
58 61  
... ... @@ -55,19 +58,33 @@
55 58 #include <asm/dec/kn02.h>
56 59 #include <asm/dec/machtype.h>
57 60 #include <asm/dec/prom.h>
  61 +#include <asm/dec/system.h>
58 62  
59 63 #include "dz.h"
60 64  
61   -static char *dz_name = "DECstation DZ serial driver version ";
62   -static char *dz_version = "1.03";
63 65  
  66 +MODULE_DESCRIPTION("DECstation DZ serial driver");
  67 +MODULE_LICENSE("GPL");
  68 +
  69 +
  70 +static char dz_name[] __initdata = "DECstation DZ serial driver version ";
  71 +static char dz_version[] __initdata = "1.04";
  72 +
64 73 struct dz_port {
  74 + struct dz_mux *mux;
65 75 struct uart_port port;
66 76 unsigned int cflag;
67 77 };
68 78  
69   -static struct dz_port dz_ports[DZ_NB_PORT];
  79 +struct dz_mux {
  80 + struct dz_port dport[DZ_NB_PORT];
  81 + atomic_t map_guard;
  82 + atomic_t irq_guard;
  83 + int initialised;
  84 +};
70 85  
  86 +static struct dz_mux dz_mux;
  87 +
71 88 static inline struct dz_port *to_dport(struct uart_port *uport)
72 89 {
73 90 return container_of(uport, struct dz_port, port);
74 91  
75 92  
76 93  
77 94  
78 95  
... ... @@ -82,21 +99,18 @@
82 99 * ------------------------------------------------------------
83 100 */
84 101  
85   -static inline unsigned short dz_in(struct dz_port *dport, unsigned offset)
  102 +static u16 dz_in(struct dz_port *dport, unsigned offset)
86 103 {
87   - volatile unsigned short *addr =
88   - (volatile unsigned short *) (dport->port.membase + offset);
  104 + void __iomem *addr = dport->port.membase + offset;
89 105  
90   - return *addr;
  106 + return readw(addr);
91 107 }
92 108  
93   -static inline void dz_out(struct dz_port *dport, unsigned offset,
94   - unsigned short value)
  109 +static void dz_out(struct dz_port *dport, unsigned offset, u16 value)
95 110 {
96   - volatile unsigned short *addr =
97   - (volatile unsigned short *) (dport->port.membase + offset);
  111 + void __iomem *addr = dport->port.membase + offset;
98 112  
99   - *addr = value;
  113 + writew(value, addr);
100 114 }
101 115  
102 116 /*
... ... @@ -112,7 +126,7 @@
112 126 static void dz_stop_tx(struct uart_port *uport)
113 127 {
114 128 struct dz_port *dport = to_dport(uport);
115   - unsigned short tmp, mask = 1 << dport->port.line;
  129 + u16 tmp, mask = 1 << dport->port.line;
116 130  
117 131 tmp = dz_in(dport, DZ_TCR); /* read the TX flag */
118 132 tmp &= ~mask; /* clear the TX flag */
... ... @@ -122,7 +136,7 @@
122 136 static void dz_start_tx(struct uart_port *uport)
123 137 {
124 138 struct dz_port *dport = to_dport(uport);
125   - unsigned short tmp, mask = 1 << dport->port.line;
  139 + u16 tmp, mask = 1 << dport->port.line;
126 140  
127 141 tmp = dz_in(dport, DZ_TCR); /* read the TX flag */
128 142 tmp |= mask; /* set the TX flag */
... ... @@ -137,7 +151,7 @@
137 151 dz_out(dport, DZ_LPR, dport->cflag);
138 152 }
139 153  
140   -static void dz_enable_ms(struct uart_port *port)
  154 +static void dz_enable_ms(struct uart_port *uport)
141 155 {
142 156 /* nothing to do */
143 157 }
144 158  
145 159  
146 160  
147 161  
... ... @@ -169,19 +183,19 @@
169 183 * This routine deals with inputs from any lines.
170 184 * ------------------------------------------------------------
171 185 */
172   -static inline void dz_receive_chars(struct dz_port *dport_in)
  186 +static inline void dz_receive_chars(struct dz_mux *mux)
173 187 {
174 188 struct uart_port *uport;
175   - struct dz_port *dport;
  189 + struct dz_port *dport = &mux->dport[0];
176 190 struct tty_struct *tty = NULL;
177 191 struct uart_icount *icount;
178 192 int lines_rx[DZ_NB_PORT] = { [0 ... DZ_NB_PORT - 1] = 0 };
179   - unsigned short status;
180 193 unsigned char ch, flag;
  194 + u16 status;
181 195 int i;
182 196  
183   - while ((status = dz_in(dport_in, DZ_RBUF)) & DZ_DVAL) {
184   - dport = &dz_ports[LINE(status)];
  197 + while ((status = dz_in(dport, DZ_RBUF)) & DZ_DVAL) {
  198 + dport = &mux->dport[LINE(status)];
185 199 uport = &dport->port;
186 200 tty = uport->info->tty; /* point to the proper dev */
187 201  
... ... @@ -235,7 +249,7 @@
235 249 }
236 250 for (i = 0; i < DZ_NB_PORT; i++)
237 251 if (lines_rx[i])
238   - tty_flip_buffer_push(dz_ports[i].port.info->tty);
  252 + tty_flip_buffer_push(mux->dport[i].port.info->tty);
239 253 }
240 254  
241 255 /*
242 256  
243 257  
244 258  
245 259  
... ... @@ -245,15 +259,15 @@
245 259 * This routine deals with outputs to any lines.
246 260 * ------------------------------------------------------------
247 261 */
248   -static inline void dz_transmit_chars(struct dz_port *dport_in)
  262 +static inline void dz_transmit_chars(struct dz_mux *mux)
249 263 {
250   - struct dz_port *dport;
  264 + struct dz_port *dport = &mux->dport[0];
251 265 struct circ_buf *xmit;
252   - unsigned short status;
253 266 unsigned char tmp;
  267 + u16 status;
254 268  
255   - status = dz_in(dport_in, DZ_CSR);
256   - dport = &dz_ports[LINE(status)];
  269 + status = dz_in(dport, DZ_CSR);
  270 + dport = &mux->dport[LINE(status)];
257 271 xmit = &dport->port.info->xmit;
258 272  
259 273 if (dport->port.x_char) { /* XON/XOFF chars */
... ... @@ -305,7 +319,7 @@
305 319 * 1. No status change interrupt; use a timer.
306 320 * 2. Handle the 3100/5000 as appropriate. --macro
307 321 */
308   - unsigned short status;
  322 + u16 status;
309 323  
310 324 /* If not the modem line just return. */
311 325 if (dport->port.line != DZ_MODEM)
312 326  
313 327  
314 328  
... ... @@ -326,19 +340,20 @@
326 340 * It deals with the multiple ports.
327 341 * ------------------------------------------------------------
328 342 */
329   -static irqreturn_t dz_interrupt(int irq, void *dev)
  343 +static irqreturn_t dz_interrupt(int irq, void *dev_id)
330 344 {
331   - struct dz_port *dport = dev;
332   - unsigned short status;
  345 + struct dz_mux *mux = dev_id;
  346 + struct dz_port *dport = &mux->dport[0];
  347 + u16 status;
333 348  
334 349 /* get the reason why we just got an irq */
335 350 status = dz_in(dport, DZ_CSR);
336 351  
337 352 if ((status & (DZ_RDONE | DZ_RIE)) == (DZ_RDONE | DZ_RIE))
338   - dz_receive_chars(dport);
  353 + dz_receive_chars(mux);
339 354  
340 355 if ((status & (DZ_TRDY | DZ_TIE)) == (DZ_TRDY | DZ_TIE))
341   - dz_transmit_chars(dport);
  356 + dz_transmit_chars(mux);
342 357  
343 358 return IRQ_HANDLED;
344 359 }
... ... @@ -371,7 +386,7 @@
371 386 * FIXME: Handle the 3100/5000 as appropriate. --macro
372 387 */
373 388 struct dz_port *dport = to_dport(uport);
374   - unsigned short tmp;
  389 + u16 tmp;
375 390  
376 391 if (dport->port.line == DZ_MODEM) {
377 392 tmp = dz_in(dport, DZ_TCR);
378 393  
379 394  
380 395  
381 396  
... ... @@ -393,14 +408,29 @@
393 408 static int dz_startup(struct uart_port *uport)
394 409 {
395 410 struct dz_port *dport = to_dport(uport);
  411 + struct dz_mux *mux = dport->mux;
396 412 unsigned long flags;
397   - unsigned short tmp;
  413 + int irq_guard;
  414 + int ret;
  415 + u16 tmp;
398 416  
  417 + irq_guard = atomic_add_return(1, &mux->irq_guard);
  418 + if (irq_guard != 1)
  419 + return 0;
  420 +
  421 + ret = request_irq(dport->port.irq, dz_interrupt,
  422 + IRQF_SHARED, "dz", mux);
  423 + if (ret) {
  424 + atomic_add(-1, &mux->irq_guard);
  425 + printk(KERN_ERR "dz: Cannot get IRQ %d!\n", dport->port.irq);
  426 + return ret;
  427 + }
  428 +
399 429 spin_lock_irqsave(&dport->port.lock, flags);
400 430  
401   - /* enable the interrupt and the scanning */
  431 + /* Enable interrupts. */
402 432 tmp = dz_in(dport, DZ_CSR);
403   - tmp |= DZ_RIE | DZ_TIE | DZ_MSE;
  433 + tmp |= DZ_RIE | DZ_TIE;
404 434 dz_out(dport, DZ_CSR, tmp);
405 435  
406 436 spin_unlock_irqrestore(&dport->port.lock, flags);
407 437  
408 438  
... ... @@ -419,11 +449,24 @@
419 449 static void dz_shutdown(struct uart_port *uport)
420 450 {
421 451 struct dz_port *dport = to_dport(uport);
  452 + struct dz_mux *mux = dport->mux;
422 453 unsigned long flags;
  454 + int irq_guard;
  455 + u16 tmp;
423 456  
424 457 spin_lock_irqsave(&dport->port.lock, flags);
425 458 dz_stop_tx(&dport->port);
426 459 spin_unlock_irqrestore(&dport->port.lock, flags);
  460 +
  461 + irq_guard = atomic_add_return(-1, &mux->irq_guard);
  462 + if (!irq_guard) {
  463 + /* Disable interrupts. */
  464 + tmp = dz_in(dport, DZ_CSR);
  465 + tmp &= ~(DZ_RIE | DZ_TIE);
  466 + dz_out(dport, DZ_CSR, tmp);
  467 +
  468 + free_irq(dport->port.irq, mux);
  469 + }
427 470 }
428 471  
429 472 /*
... ... @@ -507,6 +550,24 @@
507 550 }
508 551 }
509 552  
  553 +
  554 +static void dz_reset(struct dz_port *dport)
  555 +{
  556 + struct dz_mux *mux = dport->mux;
  557 +
  558 + if (mux->initialised)
  559 + return;
  560 +
  561 + dz_out(dport, DZ_CSR, DZ_CLR);
  562 + while (dz_in(dport, DZ_CSR) & DZ_CLR);
  563 + iob();
  564 +
  565 + /* Enable scanning. */
  566 + dz_out(dport, DZ_CSR, DZ_MSE);
  567 +
  568 + mux->initialised = 1;
  569 +}
  570 +
510 571 static void dz_set_termios(struct uart_port *uport, struct ktermios *termios,
511 572 struct ktermios *old_termios)
512 573 {
513 574  
514 575  
515 576  
516 577  
517 578  
518 579  
519 580  
520 581  
521 582  
522 583  
523 584  
... ... @@ -581,36 +642,86 @@
581 642 spin_unlock_irqrestore(&dport->port.lock, flags);
582 643 }
583 644  
584   -static const char *dz_type(struct uart_port *port)
  645 +static const char *dz_type(struct uart_port *uport)
585 646 {
586 647 return "DZ";
587 648 }
588 649  
589   -static void dz_release_port(struct uart_port *port)
  650 +static void dz_release_port(struct uart_port *uport)
590 651 {
591   - /* nothing to do */
  652 + struct dz_mux *mux = to_dport(uport)->mux;
  653 + int map_guard;
  654 +
  655 + iounmap(uport->membase);
  656 + uport->membase = NULL;
  657 +
  658 + map_guard = atomic_add_return(-1, &mux->map_guard);
  659 + if (!map_guard)
  660 + release_mem_region(uport->mapbase, dec_kn_slot_size);
592 661 }
593 662  
594   -static int dz_request_port(struct uart_port *port)
  663 +static int dz_map_port(struct uart_port *uport)
595 664 {
  665 + if (!uport->membase)
  666 + uport->membase = ioremap_nocache(uport->mapbase,
  667 + dec_kn_slot_size);
  668 + if (!uport->membase) {
  669 + printk(KERN_ERR "dz: Cannot map MMIO\n");
  670 + return -ENOMEM;
  671 + }
596 672 return 0;
597 673 }
598 674  
599   -static void dz_config_port(struct uart_port *port, int flags)
  675 +static int dz_request_port(struct uart_port *uport)
600 676 {
601   - if (flags & UART_CONFIG_TYPE)
602   - port->type = PORT_DZ;
  677 + struct dz_mux *mux = to_dport(uport)->mux;
  678 + int map_guard;
  679 + int ret;
  680 +
  681 + map_guard = atomic_add_return(1, &mux->map_guard);
  682 + if (map_guard == 1) {
  683 + if (!request_mem_region(uport->mapbase, dec_kn_slot_size,
  684 + "dz")) {
  685 + atomic_add(-1, &mux->map_guard);
  686 + printk(KERN_ERR
  687 + "dz: Unable to reserve MMIO resource\n");
  688 + return -EBUSY;
  689 + }
  690 + }
  691 + ret = dz_map_port(uport);
  692 + if (ret) {
  693 + map_guard = atomic_add_return(-1, &mux->map_guard);
  694 + if (!map_guard)
  695 + release_mem_region(uport->mapbase, dec_kn_slot_size);
  696 + return ret;
  697 + }
  698 + return 0;
603 699 }
604 700  
  701 +static void dz_config_port(struct uart_port *uport, int flags)
  702 +{
  703 + struct dz_port *dport = to_dport(uport);
  704 +
  705 + if (flags & UART_CONFIG_TYPE) {
  706 + if (dz_request_port(uport))
  707 + return;
  708 +
  709 + uport->type = PORT_DZ;
  710 +
  711 + dz_reset(dport);
  712 + }
  713 +}
  714 +
605 715 /*
606   - * verify the new serial_struct (for TIOCSSERIAL).
  716 + * Verify the new serial_struct (for TIOCSSERIAL).
607 717 */
608   -static int dz_verify_port(struct uart_port *port, struct serial_struct *ser)
  718 +static int dz_verify_port(struct uart_port *uport, struct serial_struct *ser)
609 719 {
610 720 int ret = 0;
  721 +
611 722 if (ser->type != PORT_UNKNOWN && ser->type != PORT_DZ)
612 723 ret = -EINVAL;
613   - if (ser->irq != port->irq)
  724 + if (ser->irq != uport->irq)
614 725 ret = -EINVAL;
615 726 return ret;
616 727 }
617 728  
618 729  
619 730  
620 731  
621 732  
622 733  
... ... @@ -637,40 +748,32 @@
637 748 static void __init dz_init_ports(void)
638 749 {
639 750 static int first = 1;
640   - struct dz_port *dport;
641 751 unsigned long base;
642   - int i;
  752 + int line;
643 753  
644 754 if (!first)
645 755 return;
646 756 first = 0;
647 757  
648   - if (mips_machtype == MACH_DS23100 ||
649   - mips_machtype == MACH_DS5100)
650   - base = CKSEG1ADDR(KN01_SLOT_BASE + KN01_DZ11);
  758 + if (mips_machtype == MACH_DS23100 || mips_machtype == MACH_DS5100)
  759 + base = dec_kn_slot_base + KN01_DZ11;
651 760 else
652   - base = CKSEG1ADDR(KN02_SLOT_BASE + KN02_DZ11);
  761 + base = dec_kn_slot_base + KN02_DZ11;
653 762  
654   - for (i = 0, dport = dz_ports; i < DZ_NB_PORT; i++, dport++) {
655   - spin_lock_init(&dport->port.lock);
656   - dport->port.membase = (char *) base;
657   - dport->port.iotype = UPIO_MEM;
658   - dport->port.irq = dec_interrupt[DEC_IRQ_DZ11];
659   - dport->port.line = i;
660   - dport->port.fifosize = 1;
661   - dport->port.ops = &dz_ops;
662   - dport->port.flags = UPF_BOOT_AUTOCONF;
663   - }
664   -}
  763 + for (line = 0; line < DZ_NB_PORT; line++) {
  764 + struct dz_port *dport = &dz_mux.dport[line];
  765 + struct uart_port *uport = &dport->port;
665 766  
666   -static void dz_reset(struct dz_port *dport)
667   -{
668   - dz_out(dport, DZ_CSR, DZ_CLR);
669   - while (dz_in(dport, DZ_CSR) & DZ_CLR);
670   - iob();
  767 + dport->mux = &dz_mux;
671 768  
672   - /* enable scanning */
673   - dz_out(dport, DZ_CSR, DZ_MSE);
  769 + uport->irq = dec_interrupt[DEC_IRQ_DZ11];
  770 + uport->fifosize = 1;
  771 + uport->iotype = UPIO_MEM;
  772 + uport->flags = UPF_BOOT_AUTOCONF;
  773 + uport->ops = &dz_ops;
  774 + uport->line = line;
  775 + uport->mapbase = base;
  776 + }
674 777 }
675 778  
676 779 #ifdef CONFIG_SERIAL_DZ_CONSOLE
... ... @@ -737,7 +840,7 @@
737 840 const char *str,
738 841 unsigned int count)
739 842 {
740   - struct dz_port *dport = &dz_ports[co->index];
  843 + struct dz_port *dport = &dz_mux.dport[co->index];
741 844 #ifdef DEBUG_DZ
742 845 prom_printf((char *) str);
743 846 #endif
744 847  
745 848  
746 849  
... ... @@ -746,17 +849,23 @@
746 849  
747 850 static int __init dz_console_setup(struct console *co, char *options)
748 851 {
749   - struct dz_port *dport = &dz_ports[co->index];
  852 + struct dz_port *dport = &dz_mux.dport[co->index];
  853 + struct uart_port *uport = &dport->port;
750 854 int baud = 9600;
751 855 int bits = 8;
752 856 int parity = 'n';
753 857 int flow = 'n';
  858 + int ret;
754 859  
755   - if (options)
756   - uart_parse_options(options, &baud, &parity, &bits, &flow);
  860 + ret = dz_map_port(uport);
  861 + if (ret)
  862 + return ret;
757 863  
758 864 dz_reset(dport);
759 865  
  866 + if (options)
  867 + uart_parse_options(options, &baud, &parity, &bits, &flow);
  868 +
760 869 return uart_set_options(&dport->port, co, baud, parity, bits, flow);
761 870 }
762 871  
763 872  
764 873  
765 874  
766 875  
767 876  
... ... @@ -809,37 +918,15 @@
809 918  
810 919 dz_init_ports();
811 920  
812   -#ifndef CONFIG_SERIAL_DZ_CONSOLE
813   - /* reset the chip */
814   - dz_reset(&dz_ports[0]);
815   -#endif
816   -
817 921 ret = uart_register_driver(&dz_reg);
818   - if (ret != 0)
819   - goto out;
  922 + if (ret)
  923 + return ret;
820 924  
821   - ret = request_irq(dz_ports[0].port.irq, dz_interrupt, IRQF_DISABLED,
822   - "DZ", &dz_ports[0]);
823   - if (ret != 0) {
824   - printk(KERN_ERR "dz: Cannot get IRQ %d!\n",
825   - dz_ports[0].port.irq);
826   - goto out_unregister;
827   - }
828   -
829 925 for (i = 0; i < DZ_NB_PORT; i++)
830   - uart_add_one_port(&dz_reg, &dz_ports[i].port);
  926 + uart_add_one_port(&dz_reg, &dz_mux.dport[i].port);
831 927  
832   - return ret;
833   -
834   -out_unregister:
835   - uart_unregister_driver(&dz_reg);
836   -
837   -out:
838   - return ret;
  928 + return 0;
839 929 }
840 930  
841 931 module_init(dz_init);
842   -
843   -MODULE_DESCRIPTION("DECstation DZ serial driver");
844   -MODULE_LICENSE("GPL");