diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/ide/pci/sgiioc4.c | 30 | ||||
-rw-r--r-- | drivers/serial/ioc4_serial.c | 311 | ||||
-rw-r--r-- | drivers/sn/ioc4.c | 290 |
3 files changed, 416 insertions, 215 deletions
diff --git a/drivers/ide/pci/sgiioc4.c b/drivers/ide/pci/sgiioc4.c index 4651a22bf12e..af526b671c4e 100644 --- a/drivers/ide/pci/sgiioc4.c +++ b/drivers/ide/pci/sgiioc4.c | |||
@@ -34,7 +34,7 @@ | |||
34 | #include <linux/mm.h> | 34 | #include <linux/mm.h> |
35 | #include <linux/ioport.h> | 35 | #include <linux/ioport.h> |
36 | #include <linux/blkdev.h> | 36 | #include <linux/blkdev.h> |
37 | #include <linux/ioc4_common.h> | 37 | #include <linux/ioc4.h> |
38 | #include <asm/io.h> | 38 | #include <asm/io.h> |
39 | 39 | ||
40 | #include <linux/ide.h> | 40 | #include <linux/ide.h> |
@@ -715,14 +715,34 @@ static ide_pci_device_t sgiioc4_chipsets[] __devinitdata = { | |||
715 | }; | 715 | }; |
716 | 716 | ||
717 | int | 717 | int |
718 | ioc4_ide_attach_one(struct pci_dev *dev, const struct pci_device_id *id) | 718 | ioc4_ide_attach_one(struct ioc4_driver_data *idd) |
719 | { | 719 | { |
720 | return pci_init_sgiioc4(dev, &sgiioc4_chipsets[id->driver_data]); | 720 | return pci_init_sgiioc4(idd->idd_pdev, |
721 | &sgiioc4_chipsets[idd->idd_pci_id->driver_data]); | ||
721 | } | 722 | } |
722 | 723 | ||
724 | static struct ioc4_submodule ioc4_ide_submodule = { | ||
725 | .is_name = "IOC4_ide", | ||
726 | .is_owner = THIS_MODULE, | ||
727 | .is_probe = ioc4_ide_attach_one, | ||
728 | /* .is_remove = ioc4_ide_remove_one, */ | ||
729 | }; | ||
730 | |||
731 | static int __devinit | ||
732 | ioc4_ide_init(void) | ||
733 | { | ||
734 | return ioc4_register_submodule(&ioc4_ide_submodule); | ||
735 | } | ||
736 | |||
737 | static void __devexit | ||
738 | ioc4_ide_exit(void) | ||
739 | { | ||
740 | ioc4_unregister_submodule(&ioc4_ide_submodule); | ||
741 | } | ||
742 | |||
743 | module_init(ioc4_ide_init); | ||
744 | module_exit(ioc4_ide_exit); | ||
723 | 745 | ||
724 | MODULE_AUTHOR("Aniket Malatpure - Silicon Graphics Inc. (SGI)"); | 746 | MODULE_AUTHOR("Aniket Malatpure - Silicon Graphics Inc. (SGI)"); |
725 | MODULE_DESCRIPTION("IDE PCI driver module for SGI IOC4 Base-IO Card"); | 747 | MODULE_DESCRIPTION("IDE PCI driver module for SGI IOC4 Base-IO Card"); |
726 | MODULE_LICENSE("GPL"); | 748 | MODULE_LICENSE("GPL"); |
727 | |||
728 | EXPORT_SYMBOL(ioc4_ide_attach_one); | ||
diff --git a/drivers/serial/ioc4_serial.c b/drivers/serial/ioc4_serial.c index ba4e13a22a50..da5f10eb4845 100644 --- a/drivers/serial/ioc4_serial.c +++ b/drivers/serial/ioc4_serial.c | |||
@@ -20,7 +20,7 @@ | |||
20 | #include <linux/serial_reg.h> | 20 | #include <linux/serial_reg.h> |
21 | #include <linux/module.h> | 21 | #include <linux/module.h> |
22 | #include <linux/pci.h> | 22 | #include <linux/pci.h> |
23 | #include <linux/ioc4_common.h> | 23 | #include <linux/ioc4.h> |
24 | #include <linux/serial_core.h> | 24 | #include <linux/serial_core.h> |
25 | 25 | ||
26 | /* | 26 | /* |
@@ -130,12 +130,19 @@ | |||
130 | IOC4_SIO_IR_S3_TX_EXPLICIT) | 130 | IOC4_SIO_IR_S3_TX_EXPLICIT) |
131 | 131 | ||
132 | /* Bitmasks for IOC4_OTHER_IR, IOC4_OTHER_IEC, and IOC4_OTHER_IES */ | 132 | /* Bitmasks for IOC4_OTHER_IR, IOC4_OTHER_IEC, and IOC4_OTHER_IES */ |
133 | #define IOC4_OTHER_IR_ATA_INT 0x00000001 /* ATAPI intr pass-thru */ | 133 | #define IOC4_OTHER_IR_ATA_INT 0x00000001 /* ATAPI intr pass-thru */ |
134 | #define IOC4_OTHER_IR_ATA_MEMERR 0x00000002 /* ATAPI DMA PCI error */ | 134 | #define IOC4_OTHER_IR_ATA_MEMERR 0x00000002 /* ATAPI DMA PCI error */ |
135 | #define IOC4_OTHER_IR_S0_MEMERR 0x00000004 /* Port 0 PCI error */ | 135 | #define IOC4_OTHER_IR_S0_MEMERR 0x00000004 /* Port 0 PCI error */ |
136 | #define IOC4_OTHER_IR_S1_MEMERR 0x00000008 /* Port 1 PCI error */ | 136 | #define IOC4_OTHER_IR_S1_MEMERR 0x00000008 /* Port 1 PCI error */ |
137 | #define IOC4_OTHER_IR_S2_MEMERR 0x00000010 /* Port 2 PCI error */ | 137 | #define IOC4_OTHER_IR_S2_MEMERR 0x00000010 /* Port 2 PCI error */ |
138 | #define IOC4_OTHER_IR_S3_MEMERR 0x00000020 /* Port 3 PCI error */ | 138 | #define IOC4_OTHER_IR_S3_MEMERR 0x00000020 /* Port 3 PCI error */ |
139 | #define IOC4_OTHER_IR_KBD_INT 0x00000040 /* Keyboard/mouse */ | ||
140 | #define IOC4_OTHER_IR_RESERVED 0x007fff80 /* Reserved */ | ||
141 | #define IOC4_OTHER_IR_RT_INT 0x00800000 /* INT_OUT section output */ | ||
142 | #define IOC4_OTHER_IR_GEN_INT 0xff000000 /* Generic pins */ | ||
143 | |||
144 | #define IOC4_OTHER_IR_SER_MEMERR (IOC4_OTHER_IR_S0_MEMERR | IOC4_OTHER_IR_S1_MEMERR | \ | ||
145 | IOC4_OTHER_IR_S2_MEMERR | IOC4_OTHER_IR_S3_MEMERR) | ||
139 | 146 | ||
140 | /* Bitmasks for IOC4_SIO_CR */ | 147 | /* Bitmasks for IOC4_SIO_CR */ |
141 | #define IOC4_SIO_CR_CMD_PULSE_SHIFT 0 /* byte bus strobe shift */ | 148 | #define IOC4_SIO_CR_CMD_PULSE_SHIFT 0 /* byte bus strobe shift */ |
@@ -274,67 +281,22 @@ struct ioc4_uartregs { | |||
274 | #define i4u_dlm u2.dlm | 281 | #define i4u_dlm u2.dlm |
275 | #define i4u_fcr u3.fcr | 282 | #define i4u_fcr u3.fcr |
276 | 283 | ||
277 | /* PCI memory space register map addressed using pci_bar0 */ | 284 | /* Serial port registers used for DMA serial I/O */ |
278 | struct ioc4_memregs { | 285 | struct ioc4_serial { |
279 | struct ioc4_mem { | 286 | uint32_t sbbr01_l; |
280 | /* Miscellaneous IOC4 registers */ | 287 | uint32_t sbbr01_h; |
281 | uint32_t pci_err_addr_l; | 288 | uint32_t sbbr23_l; |
282 | uint32_t pci_err_addr_h; | 289 | uint32_t sbbr23_h; |
283 | uint32_t sio_ir; | 290 | |
284 | uint32_t other_ir; | 291 | struct ioc4_serialregs port_0; |
285 | 292 | struct ioc4_serialregs port_1; | |
286 | /* These registers are read-only for general kernel code. */ | 293 | struct ioc4_serialregs port_2; |
287 | uint32_t sio_ies_ro; | 294 | struct ioc4_serialregs port_3; |
288 | uint32_t other_ies_ro; | 295 | struct ioc4_uartregs uart_0; |
289 | uint32_t sio_iec_ro; | 296 | struct ioc4_uartregs uart_1; |
290 | uint32_t other_iec_ro; | 297 | struct ioc4_uartregs uart_2; |
291 | uint32_t sio_cr; | 298 | struct ioc4_uartregs uart_3; |
292 | uint32_t misc_fill1; | 299 | } ioc4_serial; |
293 | uint32_t int_out; | ||
294 | uint32_t misc_fill2; | ||
295 | uint32_t gpcr_s; | ||
296 | uint32_t gpcr_c; | ||
297 | uint32_t gpdr; | ||
298 | uint32_t misc_fill3; | ||
299 | uint32_t gppr_0; | ||
300 | uint32_t gppr_1; | ||
301 | uint32_t gppr_2; | ||
302 | uint32_t gppr_3; | ||
303 | uint32_t gppr_4; | ||
304 | uint32_t gppr_5; | ||
305 | uint32_t gppr_6; | ||
306 | uint32_t gppr_7; | ||
307 | } ioc4_mem; | ||
308 | |||
309 | char misc_fill4[0x100 - 0x5C - 4]; | ||
310 | |||
311 | /* ATA/ATAP registers */ | ||
312 | uint32_t ata_notused[9]; | ||
313 | char ata_fill1[0x140 - 0x120 - 4]; | ||
314 | uint32_t ata_notused1[8]; | ||
315 | char ata_fill2[0x200 - 0x15C - 4]; | ||
316 | |||
317 | /* Keyboard and mouse registers */ | ||
318 | uint32_t km_notused[5];; | ||
319 | char km_fill1[0x300 - 0x210 - 4]; | ||
320 | |||
321 | /* Serial port registers used for DMA serial I/O */ | ||
322 | struct ioc4_serial { | ||
323 | uint32_t sbbr01_l; | ||
324 | uint32_t sbbr01_h; | ||
325 | uint32_t sbbr23_l; | ||
326 | uint32_t sbbr23_h; | ||
327 | |||
328 | struct ioc4_serialregs port_0; | ||
329 | struct ioc4_serialregs port_1; | ||
330 | struct ioc4_serialregs port_2; | ||
331 | struct ioc4_serialregs port_3; | ||
332 | struct ioc4_uartregs uart_0; | ||
333 | struct ioc4_uartregs uart_1; | ||
334 | struct ioc4_uartregs uart_2; | ||
335 | struct ioc4_uartregs uart_3; | ||
336 | } ioc4_serial; | ||
337 | }; | ||
338 | 300 | ||
339 | /* UART clock speed */ | 301 | /* UART clock speed */ |
340 | #define IOC4_SER_XIN_CLK IOC4_SER_XIN_CLK_66 | 302 | #define IOC4_SER_XIN_CLK IOC4_SER_XIN_CLK_66 |
@@ -412,8 +374,8 @@ enum sio_proto { | |||
412 | | UART_LCR_WLEN7 | UART_LCR_WLEN8) | 374 | | UART_LCR_WLEN7 | UART_LCR_WLEN8) |
413 | #define LCR_MASK_STOP_BITS (UART_LCR_STOP) | 375 | #define LCR_MASK_STOP_BITS (UART_LCR_STOP) |
414 | 376 | ||
415 | #define PENDING(_p) (readl(&(_p)->ip_mem->sio_ir) & _p->ip_ienb) | 377 | #define PENDING(_p) (readl(&(_p)->ip_mem->sio_ir.raw) & _p->ip_ienb) |
416 | #define READ_SIO_IR(_p) readl(&(_p)->ip_mem->sio_ir) | 378 | #define READ_SIO_IR(_p) readl(&(_p)->ip_mem->sio_ir.raw) |
417 | 379 | ||
418 | /* Default to 4k buffers */ | 380 | /* Default to 4k buffers */ |
419 | #ifdef IOC4_1K_BUFFERS | 381 | #ifdef IOC4_1K_BUFFERS |
@@ -447,7 +409,7 @@ struct ioc4_control { | |||
447 | */ | 409 | */ |
448 | #define MAX_IOC4_INTR_ENTS (8 * sizeof(uint32_t)) | 410 | #define MAX_IOC4_INTR_ENTS (8 * sizeof(uint32_t)) |
449 | struct ioc4_soft { | 411 | struct ioc4_soft { |
450 | struct ioc4_mem __iomem *is_ioc4_mem_addr; | 412 | struct ioc4_misc_regs __iomem *is_ioc4_misc_addr; |
451 | struct ioc4_serial __iomem *is_ioc4_serial_addr; | 413 | struct ioc4_serial __iomem *is_ioc4_serial_addr; |
452 | 414 | ||
453 | /* Each interrupt type has an entry in the array */ | 415 | /* Each interrupt type has an entry in the array */ |
@@ -486,7 +448,7 @@ struct ioc4_port { | |||
486 | struct ioc4_soft *ip_ioc4_soft; | 448 | struct ioc4_soft *ip_ioc4_soft; |
487 | 449 | ||
488 | /* pci mem addresses */ | 450 | /* pci mem addresses */ |
489 | struct ioc4_mem __iomem *ip_mem; | 451 | struct ioc4_misc_regs __iomem *ip_mem; |
490 | struct ioc4_serial __iomem *ip_serial; | 452 | struct ioc4_serial __iomem *ip_serial; |
491 | struct ioc4_serialregs __iomem *ip_serial_regs; | 453 | struct ioc4_serialregs __iomem *ip_serial_regs; |
492 | struct ioc4_uartregs __iomem *ip_uart_regs; | 454 | struct ioc4_uartregs __iomem *ip_uart_regs; |
@@ -553,7 +515,7 @@ struct hooks { | |||
553 | uint32_t intr_dma_error; | 515 | uint32_t intr_dma_error; |
554 | uint32_t intr_clear; | 516 | uint32_t intr_clear; |
555 | uint32_t intr_all; | 517 | uint32_t intr_all; |
556 | char rs422_select_pin; | 518 | int rs422_select_pin; |
557 | }; | 519 | }; |
558 | 520 | ||
559 | static struct hooks hooks_array[IOC4_NUM_SERIAL_PORTS] = { | 521 | static struct hooks hooks_array[IOC4_NUM_SERIAL_PORTS] = { |
@@ -669,7 +631,7 @@ static void handle_intr(void *arg, uint32_t sio_ir); | |||
669 | static inline void | 631 | static inline void |
670 | write_ireg(struct ioc4_soft *ioc4_soft, uint32_t val, int which, int type) | 632 | write_ireg(struct ioc4_soft *ioc4_soft, uint32_t val, int which, int type) |
671 | { | 633 | { |
672 | struct ioc4_mem __iomem *mem = ioc4_soft->is_ioc4_mem_addr; | 634 | struct ioc4_misc_regs __iomem *mem = ioc4_soft->is_ioc4_misc_addr; |
673 | unsigned long flags; | 635 | unsigned long flags; |
674 | 636 | ||
675 | spin_lock_irqsave(&ioc4_soft->is_ir_lock, flags); | 637 | spin_lock_irqsave(&ioc4_soft->is_ir_lock, flags); |
@@ -678,11 +640,11 @@ write_ireg(struct ioc4_soft *ioc4_soft, uint32_t val, int which, int type) | |||
678 | case IOC4_SIO_INTR_TYPE: | 640 | case IOC4_SIO_INTR_TYPE: |
679 | switch (which) { | 641 | switch (which) { |
680 | case IOC4_W_IES: | 642 | case IOC4_W_IES: |
681 | writel(val, &mem->sio_ies_ro); | 643 | writel(val, &mem->sio_ies.raw); |
682 | break; | 644 | break; |
683 | 645 | ||
684 | case IOC4_W_IEC: | 646 | case IOC4_W_IEC: |
685 | writel(val, &mem->sio_iec_ro); | 647 | writel(val, &mem->sio_iec.raw); |
686 | break; | 648 | break; |
687 | } | 649 | } |
688 | break; | 650 | break; |
@@ -690,11 +652,11 @@ write_ireg(struct ioc4_soft *ioc4_soft, uint32_t val, int which, int type) | |||
690 | case IOC4_OTHER_INTR_TYPE: | 652 | case IOC4_OTHER_INTR_TYPE: |
691 | switch (which) { | 653 | switch (which) { |
692 | case IOC4_W_IES: | 654 | case IOC4_W_IES: |
693 | writel(val, &mem->other_ies_ro); | 655 | writel(val, &mem->other_ies.raw); |
694 | break; | 656 | break; |
695 | 657 | ||
696 | case IOC4_W_IEC: | 658 | case IOC4_W_IEC: |
697 | writel(val, &mem->other_iec_ro); | 659 | writel(val, &mem->other_iec.raw); |
698 | break; | 660 | break; |
699 | } | 661 | } |
700 | break; | 662 | break; |
@@ -747,7 +709,8 @@ static int set_baud(struct ioc4_port *port, int baud) | |||
747 | */ | 709 | */ |
748 | static struct ioc4_port *get_ioc4_port(struct uart_port *the_port) | 710 | static struct ioc4_port *get_ioc4_port(struct uart_port *the_port) |
749 | { | 711 | { |
750 | struct ioc4_control *control = dev_get_drvdata(the_port->dev); | 712 | struct ioc4_driver_data *idd = dev_get_drvdata(the_port->dev); |
713 | struct ioc4_control *control = idd->idd_serial_data; | ||
751 | int ii; | 714 | int ii; |
752 | 715 | ||
753 | if (control) { | 716 | if (control) { |
@@ -782,7 +745,7 @@ static struct ioc4_port *get_ioc4_port(struct uart_port *the_port) | |||
782 | static inline uint32_t | 745 | static inline uint32_t |
783 | pending_intrs(struct ioc4_soft *soft, int type) | 746 | pending_intrs(struct ioc4_soft *soft, int type) |
784 | { | 747 | { |
785 | struct ioc4_mem __iomem *mem = soft->is_ioc4_mem_addr; | 748 | struct ioc4_misc_regs __iomem *mem = soft->is_ioc4_misc_addr; |
786 | unsigned long flag; | 749 | unsigned long flag; |
787 | uint32_t intrs = 0; | 750 | uint32_t intrs = 0; |
788 | 751 | ||
@@ -793,11 +756,11 @@ pending_intrs(struct ioc4_soft *soft, int type) | |||
793 | 756 | ||
794 | switch (type) { | 757 | switch (type) { |
795 | case IOC4_SIO_INTR_TYPE: | 758 | case IOC4_SIO_INTR_TYPE: |
796 | intrs = readl(&mem->sio_ir) & readl(&mem->sio_ies_ro); | 759 | intrs = readl(&mem->sio_ir.raw) & readl(&mem->sio_ies.raw); |
797 | break; | 760 | break; |
798 | 761 | ||
799 | case IOC4_OTHER_INTR_TYPE: | 762 | case IOC4_OTHER_INTR_TYPE: |
800 | intrs = readl(&mem->other_ir) & readl(&mem->other_ies_ro); | 763 | intrs = readl(&mem->other_ir.raw) & readl(&mem->other_ies.raw); |
801 | 764 | ||
802 | /* Don't process any ATA interrupte */ | 765 | /* Don't process any ATA interrupte */ |
803 | intrs &= ~(IOC4_OTHER_IR_ATA_INT | IOC4_OTHER_IR_ATA_MEMERR); | 766 | intrs &= ~(IOC4_OTHER_IR_ATA_INT | IOC4_OTHER_IR_ATA_MEMERR); |
@@ -826,7 +789,7 @@ static int inline port_init(struct ioc4_port *port) | |||
826 | 789 | ||
827 | /* Wait until any pending bus activity for this port has ceased */ | 790 | /* Wait until any pending bus activity for this port has ceased */ |
828 | do | 791 | do |
829 | sio_cr = readl(&port->ip_mem->sio_cr); | 792 | sio_cr = readl(&port->ip_mem->sio_cr.raw); |
830 | while (!(sio_cr & IOC4_SIO_CR_SIO_DIAG_IDLE)); | 793 | while (!(sio_cr & IOC4_SIO_CR_SIO_DIAG_IDLE)); |
831 | 794 | ||
832 | /* Finish reset sequence */ | 795 | /* Finish reset sequence */ |
@@ -899,7 +862,7 @@ static int inline port_init(struct ioc4_port *port) | |||
899 | write_ireg(port->ip_ioc4_soft, hooks->intr_clear, | 862 | write_ireg(port->ip_ioc4_soft, hooks->intr_clear, |
900 | IOC4_W_IEC, IOC4_SIO_INTR_TYPE); | 863 | IOC4_W_IEC, IOC4_SIO_INTR_TYPE); |
901 | port->ip_ienb &= ~hooks->intr_clear; | 864 | port->ip_ienb &= ~hooks->intr_clear; |
902 | writel(hooks->intr_clear, &port->ip_mem->sio_ir); | 865 | writel(hooks->intr_clear, &port->ip_mem->sio_ir.raw); |
903 | return 0; | 866 | return 0; |
904 | } | 867 | } |
905 | 868 | ||
@@ -918,23 +881,23 @@ static void handle_dma_error_intr(void *arg, uint32_t other_ir) | |||
918 | spin_lock_irqsave(&port->ip_lock, flags); | 881 | spin_lock_irqsave(&port->ip_lock, flags); |
919 | 882 | ||
920 | /* ACK the interrupt */ | 883 | /* ACK the interrupt */ |
921 | writel(hooks->intr_dma_error, &port->ip_mem->other_ir); | 884 | writel(hooks->intr_dma_error, &port->ip_mem->other_ir.raw); |
922 | 885 | ||
923 | if (readl(&port->ip_mem->pci_err_addr_l) & IOC4_PCI_ERR_ADDR_VLD) { | 886 | if (readl(&port->ip_mem->pci_err_addr_l.raw) & IOC4_PCI_ERR_ADDR_VLD) { |
924 | printk(KERN_ERR | 887 | printk(KERN_ERR |
925 | "PCI error address is 0x%lx, " | 888 | "PCI error address is 0x%lx, " |
926 | "master is serial port %c %s\n", | 889 | "master is serial port %c %s\n", |
927 | (((uint64_t)readl(&port->ip_mem->pci_err_addr_h) | 890 | (((uint64_t)readl(&port->ip_mem->pci_err_addr_h) |
928 | << 32) | 891 | << 32) |
929 | | readl(&port->ip_mem->pci_err_addr_l)) | 892 | | readl(&port->ip_mem->pci_err_addr_l.raw)) |
930 | & IOC4_PCI_ERR_ADDR_ADDR_MSK, '1' + | 893 | & IOC4_PCI_ERR_ADDR_ADDR_MSK, '1' + |
931 | ((char)(readl(&port->ip_mem-> pci_err_addr_l) & | 894 | ((char)(readl(&port->ip_mem->pci_err_addr_l.raw) & |
932 | IOC4_PCI_ERR_ADDR_MST_NUM_MSK) >> 1), | 895 | IOC4_PCI_ERR_ADDR_MST_NUM_MSK) >> 1), |
933 | (readl(&port->ip_mem->pci_err_addr_l) | 896 | (readl(&port->ip_mem->pci_err_addr_l.raw) |
934 | & IOC4_PCI_ERR_ADDR_MST_TYP_MSK) | 897 | & IOC4_PCI_ERR_ADDR_MST_TYP_MSK) |
935 | ? "RX" : "TX"); | 898 | ? "RX" : "TX"); |
936 | 899 | ||
937 | if (readl(&port->ip_mem->pci_err_addr_l) | 900 | if (readl(&port->ip_mem->pci_err_addr_l.raw) |
938 | & IOC4_PCI_ERR_ADDR_MUL_ERR) { | 901 | & IOC4_PCI_ERR_ADDR_MUL_ERR) { |
939 | printk(KERN_ERR | 902 | printk(KERN_ERR |
940 | "Multiple errors occurred\n"); | 903 | "Multiple errors occurred\n"); |
@@ -1018,26 +981,26 @@ static irqreturn_t ioc4_intr(int irq, void *arg, struct pt_regs *regs) | |||
1018 | "other_ies = 0x%x\n", | 981 | "other_ies = 0x%x\n", |
1019 | (intr_type == IOC4_SIO_INTR_TYPE) ? "sio" : | 982 | (intr_type == IOC4_SIO_INTR_TYPE) ? "sio" : |
1020 | "other", this_ir, | 983 | "other", this_ir, |
1021 | readl(&soft->is_ioc4_mem_addr->sio_ir), | 984 | readl(&soft->is_ioc4_misc_addr->sio_ir.raw), |
1022 | readl(&soft->is_ioc4_mem_addr->sio_ies_ro), | 985 | readl(&soft->is_ioc4_misc_addr->sio_ies.raw), |
1023 | readl(&soft->is_ioc4_mem_addr->other_ir), | 986 | readl(&soft->is_ioc4_misc_addr->other_ir.raw), |
1024 | readl(&soft->is_ioc4_mem_addr->other_ies_ro)); | 987 | readl(&soft->is_ioc4_misc_addr->other_ies.raw)); |
1025 | } | 988 | } |
1026 | } | 989 | } |
1027 | #ifdef DEBUG_INTERRUPTS | 990 | #ifdef DEBUG_INTERRUPTS |
1028 | { | 991 | { |
1029 | struct ioc4_mem __iomem *mem = soft->is_ioc4_mem_addr; | 992 | struct ioc4_misc_regs __iomem *mem = soft->is_ioc4_misc_addr; |
1030 | spinlock_t *lp = &soft->is_ir_lock; | 993 | spinlock_t *lp = &soft->is_ir_lock; |
1031 | unsigned long flag; | 994 | unsigned long flag; |
1032 | 995 | ||
1033 | spin_lock_irqsave(&soft->is_ir_lock, flag); | 996 | spin_lock_irqsave(&soft->is_ir_lock, flag); |
1034 | printk ("%s : %d : mem 0x%p sio_ir 0x%x sio_ies_ro 0x%x " | 997 | printk ("%s : %d : mem 0x%p sio_ir 0x%x sio_ies 0x%x " |
1035 | "other_ir 0x%x other_ies_ro 0x%x mask 0x%x\n", | 998 | "other_ir 0x%x other_ies 0x%x mask 0x%x\n", |
1036 | __FUNCTION__, __LINE__, | 999 | __FUNCTION__, __LINE__, |
1037 | (void *)mem, readl(&mem->sio_ir), | 1000 | (void *)mem, readl(&mem->sio_ir.raw), |
1038 | readl(&mem->sio_ies_ro), | 1001 | readl(&mem->sio_ies.raw), |
1039 | readl(&mem->other_ir), | 1002 | readl(&mem->other_ir.raw), |
1040 | readl(&mem->other_ies_ro), | 1003 | readl(&mem->other_ies.raw), |
1041 | IOC4_OTHER_IR_ATA_INT | IOC4_OTHER_IR_ATA_MEMERR); | 1004 | IOC4_OTHER_IR_ATA_INT | IOC4_OTHER_IR_ATA_MEMERR); |
1042 | spin_unlock_irqrestore(&soft->is_ir_lock, flag); | 1005 | spin_unlock_irqrestore(&soft->is_ir_lock, flag); |
1043 | } | 1006 | } |
@@ -1056,7 +1019,7 @@ static irqreturn_t ioc4_intr(int irq, void *arg, struct pt_regs *regs) | |||
1056 | */ | 1019 | */ |
1057 | static int inline ioc4_attach_local(struct pci_dev *pdev, | 1020 | static int inline ioc4_attach_local(struct pci_dev *pdev, |
1058 | struct ioc4_control *control, | 1021 | struct ioc4_control *control, |
1059 | struct ioc4_soft *soft, void __iomem *ioc4_mem, | 1022 | struct ioc4_soft *soft, void __iomem *ioc4_misc, |
1060 | void __iomem *ioc4_serial) | 1023 | void __iomem *ioc4_serial) |
1061 | { | 1024 | { |
1062 | struct ioc4_port *port; | 1025 | struct ioc4_port *port; |
@@ -1076,7 +1039,7 @@ static int inline ioc4_attach_local(struct pci_dev *pdev, | |||
1076 | ioc4_revid, ioc4_revid_min); | 1039 | ioc4_revid, ioc4_revid_min); |
1077 | return -EPERM; | 1040 | return -EPERM; |
1078 | } | 1041 | } |
1079 | BUG_ON(ioc4_mem == NULL); | 1042 | BUG_ON(ioc4_misc == NULL); |
1080 | BUG_ON(ioc4_serial == NULL); | 1043 | BUG_ON(ioc4_serial == NULL); |
1081 | 1044 | ||
1082 | /* Create port structures for each port */ | 1045 | /* Create port structures for each port */ |
@@ -1103,7 +1066,7 @@ static int inline ioc4_attach_local(struct pci_dev *pdev, | |||
1103 | port->ip_pci_bus_speed = IOC4_SER_XIN_CLK; | 1066 | port->ip_pci_bus_speed = IOC4_SER_XIN_CLK; |
1104 | port->ip_baud = 9600; | 1067 | port->ip_baud = 9600; |
1105 | port->ip_control = control; | 1068 | port->ip_control = control; |
1106 | port->ip_mem = ioc4_mem; | 1069 | port->ip_mem = ioc4_misc; |
1107 | port->ip_serial = ioc4_serial; | 1070 | port->ip_serial = ioc4_serial; |
1108 | 1071 | ||
1109 | /* point to the right hook */ | 1072 | /* point to the right hook */ |
@@ -1604,14 +1567,12 @@ static int ioc4_set_proto(struct ioc4_port *port, enum sio_proto proto) | |||
1604 | switch (proto) { | 1567 | switch (proto) { |
1605 | case PROTO_RS232: | 1568 | case PROTO_RS232: |
1606 | /* Clear the appropriate GIO pin */ | 1569 | /* Clear the appropriate GIO pin */ |
1607 | writel(0, (&port->ip_mem->gppr_0 + | 1570 | writel(0, (&port->ip_mem->gppr[hooks->rs422_select_pin].raw)); |
1608 | hooks->rs422_select_pin)); | ||
1609 | break; | 1571 | break; |
1610 | 1572 | ||
1611 | case PROTO_RS422: | 1573 | case PROTO_RS422: |
1612 | /* Set the appropriate GIO pin */ | 1574 | /* Set the appropriate GIO pin */ |
1613 | writel(1, (&port->ip_mem->gppr_0 + | 1575 | writel(1, (&port->ip_mem->gppr[hooks->rs422_select_pin].raw)); |
1614 | hooks->rs422_select_pin)); | ||
1615 | break; | 1576 | break; |
1616 | 1577 | ||
1617 | default: | 1578 | default: |
@@ -1885,7 +1846,7 @@ static void handle_intr(void *arg, uint32_t sio_ir) | |||
1885 | if (sio_ir & hooks->intr_delta_dcd) { | 1846 | if (sio_ir & hooks->intr_delta_dcd) { |
1886 | /* ACK the interrupt */ | 1847 | /* ACK the interrupt */ |
1887 | writel(hooks->intr_delta_dcd, | 1848 | writel(hooks->intr_delta_dcd, |
1888 | &port->ip_mem->sio_ir); | 1849 | &port->ip_mem->sio_ir.raw); |
1889 | 1850 | ||
1890 | shadow = readl(&port->ip_serial_regs->shadow); | 1851 | shadow = readl(&port->ip_serial_regs->shadow); |
1891 | 1852 | ||
@@ -1907,7 +1868,7 @@ static void handle_intr(void *arg, uint32_t sio_ir) | |||
1907 | if (sio_ir & hooks->intr_delta_cts) { | 1868 | if (sio_ir & hooks->intr_delta_cts) { |
1908 | /* ACK the interrupt */ | 1869 | /* ACK the interrupt */ |
1909 | writel(hooks->intr_delta_cts, | 1870 | writel(hooks->intr_delta_cts, |
1910 | &port->ip_mem->sio_ir); | 1871 | &port->ip_mem->sio_ir.raw); |
1911 | 1872 | ||
1912 | shadow = readl(&port->ip_serial_regs->shadow); | 1873 | shadow = readl(&port->ip_serial_regs->shadow); |
1913 | 1874 | ||
@@ -1928,7 +1889,7 @@ static void handle_intr(void *arg, uint32_t sio_ir) | |||
1928 | if (sio_ir & hooks->intr_rx_timer) { | 1889 | if (sio_ir & hooks->intr_rx_timer) { |
1929 | /* ACK the interrupt */ | 1890 | /* ACK the interrupt */ |
1930 | writel(hooks->intr_rx_timer, | 1891 | writel(hooks->intr_rx_timer, |
1931 | &port->ip_mem->sio_ir); | 1892 | &port->ip_mem->sio_ir.raw); |
1932 | 1893 | ||
1933 | if ((port->ip_notify & N_DATA_READY) | 1894 | if ((port->ip_notify & N_DATA_READY) |
1934 | && (port->ip_port)) { | 1895 | && (port->ip_port)) { |
@@ -1974,7 +1935,7 @@ static void handle_intr(void *arg, uint32_t sio_ir) | |||
1974 | 1935 | ||
1975 | /* ACK the interrupt */ | 1936 | /* ACK the interrupt */ |
1976 | writel(hooks->intr_tx_explicit, | 1937 | writel(hooks->intr_tx_explicit, |
1977 | &port->ip_mem->sio_ir); | 1938 | &port->ip_mem->sio_ir.raw); |
1978 | 1939 | ||
1979 | if (port->ip_notify & N_OUTPUT_LOWAT) | 1940 | if (port->ip_notify & N_OUTPUT_LOWAT) |
1980 | ioc4_cb_output_lowat(port); | 1941 | ioc4_cb_output_lowat(port); |
@@ -2634,7 +2595,8 @@ ioc4_serial_core_attach(struct pci_dev *pdev) | |||
2634 | { | 2595 | { |
2635 | struct ioc4_port *port; | 2596 | struct ioc4_port *port; |
2636 | struct uart_port *the_port; | 2597 | struct uart_port *the_port; |
2637 | struct ioc4_control *control = pci_get_drvdata(pdev); | 2598 | struct ioc4_driver_data *idd = pci_get_drvdata(pdev); |
2599 | struct ioc4_control *control = idd->idd_serial_data; | ||
2638 | int ii; | 2600 | int ii; |
2639 | 2601 | ||
2640 | DPRINT_CONFIG(("%s: attach pdev 0x%p - control 0x%p\n", | 2602 | DPRINT_CONFIG(("%s: attach pdev 0x%p - control 0x%p\n", |
@@ -2680,55 +2642,29 @@ ioc4_serial_core_attach(struct pci_dev *pdev) | |||
2680 | 2642 | ||
2681 | /** | 2643 | /** |
2682 | * ioc4_serial_attach_one - register attach function | 2644 | * ioc4_serial_attach_one - register attach function |
2683 | * called per card found from ioc4_serial_detect as part | 2645 | * called per card found from IOC4 master module. |
2684 | * of module_init(). | 2646 | * @idd: Master module data for this IOC4 |
2685 | * @pdev: handle for this card | ||
2686 | * @pci_id: pci id for this card | ||
2687 | */ | 2647 | */ |
2688 | int | 2648 | int |
2689 | ioc4_serial_attach_one(struct pci_dev *pdev, const struct pci_device_id *pci_id) | 2649 | ioc4_serial_attach_one(struct ioc4_driver_data *idd) |
2690 | { | 2650 | { |
2691 | struct ioc4_mem __iomem *mem; | 2651 | unsigned long tmp_addr1; |
2692 | unsigned long tmp_addr, tmp_addr1; | ||
2693 | struct ioc4_serial __iomem *serial; | 2652 | struct ioc4_serial __iomem *serial; |
2694 | struct ioc4_soft *soft; | 2653 | struct ioc4_soft *soft; |
2695 | struct ioc4_control *control; | 2654 | struct ioc4_control *control; |
2696 | int tmp, ret = 0; | 2655 | int ret = 0; |
2697 | 2656 | ||
2698 | 2657 | ||
2699 | DPRINT_CONFIG(("%s (0x%p, 0x%p)\n", __FUNCTION__, pdev, pci_id)); | 2658 | DPRINT_CONFIG(("%s (0x%p, 0x%p)\n", __FUNCTION__, idd->idd_pdev, idd->idd_pci_id)); |
2700 | |||
2701 | /* Map in the ioc4 memory */ | ||
2702 | tmp_addr = pci_resource_start(pdev, 0); | ||
2703 | if (!tmp_addr) { | ||
2704 | printk(KERN_WARNING | ||
2705 | "ioc4 (%p) : unable to get PIO mapping for " | ||
2706 | "MEM space\n", (void *)pdev); | ||
2707 | return -ENODEV; | ||
2708 | } | ||
2709 | if (!request_region(tmp_addr, sizeof(struct ioc4_mem), "sioc4_mem")) { | ||
2710 | printk(KERN_ALERT | ||
2711 | "ioc4 (%p): unable to get request region for " | ||
2712 | "MEM space\n", (void *)pdev); | ||
2713 | return -ENODEV; | ||
2714 | } | ||
2715 | mem = ioremap(tmp_addr, sizeof(struct ioc4_mem)); | ||
2716 | if (!mem) { | ||
2717 | printk(KERN_WARNING | ||
2718 | "ioc4 (%p) : unable to remap ioc4 memory\n", | ||
2719 | (void *)pdev); | ||
2720 | ret = -ENODEV; | ||
2721 | goto out1; | ||
2722 | } | ||
2723 | 2659 | ||
2724 | /* request serial registers */ | 2660 | /* request serial registers */ |
2725 | tmp_addr1 = pci_resource_start(pdev, 0) + IOC4_SERIAL_OFFSET; | 2661 | tmp_addr1 = idd->idd_bar0 + IOC4_SERIAL_OFFSET; |
2726 | 2662 | ||
2727 | if (!request_region(tmp_addr1, sizeof(struct ioc4_serial), | 2663 | if (!request_region(tmp_addr1, sizeof(struct ioc4_serial), |
2728 | "sioc4_uart")) { | 2664 | "sioc4_uart")) { |
2729 | printk(KERN_WARNING | 2665 | printk(KERN_WARNING |
2730 | "ioc4 (%p): unable to get request region for " | 2666 | "ioc4 (%p): unable to get request region for " |
2731 | "uart space\n", (void *)pdev); | 2667 | "uart space\n", (void *)idd->idd_pdev); |
2732 | ret = -ENODEV; | 2668 | ret = -ENODEV; |
2733 | goto out1; | 2669 | goto out1; |
2734 | } | 2670 | } |
@@ -2736,12 +2672,12 @@ ioc4_serial_attach_one(struct pci_dev *pdev, const struct pci_device_id *pci_id) | |||
2736 | if (!serial) { | 2672 | if (!serial) { |
2737 | printk(KERN_WARNING | 2673 | printk(KERN_WARNING |
2738 | "ioc4 (%p) : unable to remap ioc4 serial register\n", | 2674 | "ioc4 (%p) : unable to remap ioc4 serial register\n", |
2739 | (void *)pdev); | 2675 | (void *)idd->idd_pdev); |
2740 | ret = -ENODEV; | 2676 | ret = -ENODEV; |
2741 | goto out2; | 2677 | goto out2; |
2742 | } | 2678 | } |
2743 | DPRINT_CONFIG(("%s : mem 0x%p, serial 0x%p\n", | 2679 | DPRINT_CONFIG(("%s : mem 0x%p, serial 0x%p\n", |
2744 | __FUNCTION__, (void *)mem, (void *)serial)); | 2680 | __FUNCTION__, (void *)idd->idd_misc_regs, (void *)serial)); |
2745 | 2681 | ||
2746 | /* Get memory for the new card */ | 2682 | /* Get memory for the new card */ |
2747 | control = kmalloc(sizeof(struct ioc4_control) * IOC4_NUM_SERIAL_PORTS, | 2683 | control = kmalloc(sizeof(struct ioc4_control) * IOC4_NUM_SERIAL_PORTS, |
@@ -2754,59 +2690,57 @@ ioc4_serial_attach_one(struct pci_dev *pdev, const struct pci_device_id *pci_id) | |||
2754 | goto out2; | 2690 | goto out2; |
2755 | } | 2691 | } |
2756 | memset(control, 0, sizeof(struct ioc4_control)); | 2692 | memset(control, 0, sizeof(struct ioc4_control)); |
2757 | pci_set_drvdata(pdev, control); | 2693 | idd->idd_serial_data = control; |
2758 | 2694 | ||
2759 | /* Allocate the soft structure */ | 2695 | /* Allocate the soft structure */ |
2760 | soft = kmalloc(sizeof(struct ioc4_soft), GFP_KERNEL); | 2696 | soft = kmalloc(sizeof(struct ioc4_soft), GFP_KERNEL); |
2761 | if (!soft) { | 2697 | if (!soft) { |
2762 | printk(KERN_WARNING | 2698 | printk(KERN_WARNING |
2763 | "ioc4 (%p): unable to get memory for the soft struct\n", | 2699 | "ioc4 (%p): unable to get memory for the soft struct\n", |
2764 | (void *)pdev); | 2700 | (void *)idd->idd_pdev); |
2765 | ret = -ENOMEM; | 2701 | ret = -ENOMEM; |
2766 | goto out3; | 2702 | goto out3; |
2767 | } | 2703 | } |
2768 | memset(soft, 0, sizeof(struct ioc4_soft)); | 2704 | memset(soft, 0, sizeof(struct ioc4_soft)); |
2769 | 2705 | ||
2770 | spin_lock_init(&soft->is_ir_lock); | 2706 | spin_lock_init(&soft->is_ir_lock); |
2771 | soft->is_ioc4_mem_addr = mem; | 2707 | soft->is_ioc4_misc_addr = idd->idd_misc_regs; |
2772 | soft->is_ioc4_serial_addr = serial; | 2708 | soft->is_ioc4_serial_addr = serial; |
2773 | 2709 | ||
2774 | /* Init the IOC4 */ | 2710 | /* Init the IOC4 */ |
2775 | pci_read_config_dword(pdev, PCI_COMMAND, &tmp); | 2711 | writel(0xf << IOC4_SIO_CR_CMD_PULSE_SHIFT, |
2776 | pci_write_config_dword(pdev, PCI_COMMAND, | 2712 | &idd->idd_misc_regs->sio_cr.raw); |
2777 | tmp | PCI_COMMAND_PARITY | PCI_COMMAND_SERR); | ||
2778 | |||
2779 | writel(0xf << IOC4_SIO_CR_CMD_PULSE_SHIFT, &mem->sio_cr); | ||
2780 | 2713 | ||
2781 | /* Enable serial port mode select generic PIO pins as outputs */ | 2714 | /* Enable serial port mode select generic PIO pins as outputs */ |
2782 | writel(IOC4_GPCR_UART0_MODESEL | IOC4_GPCR_UART1_MODESEL | 2715 | writel(IOC4_GPCR_UART0_MODESEL | IOC4_GPCR_UART1_MODESEL |
2783 | | IOC4_GPCR_UART2_MODESEL | IOC4_GPCR_UART3_MODESEL, | 2716 | | IOC4_GPCR_UART2_MODESEL | IOC4_GPCR_UART3_MODESEL, |
2784 | &mem->gpcr_s); | 2717 | &idd->idd_misc_regs->gpcr_s.raw); |
2785 | 2718 | ||
2786 | /* Clear and disable all interrupts */ | 2719 | /* Clear and disable all serial interrupts */ |
2787 | write_ireg(soft, ~0, IOC4_W_IEC, IOC4_SIO_INTR_TYPE); | 2720 | write_ireg(soft, ~0, IOC4_W_IEC, IOC4_SIO_INTR_TYPE); |
2788 | writel(~0, &mem->sio_ir); | 2721 | writel(~0, &idd->idd_misc_regs->sio_ir.raw); |
2789 | write_ireg(soft, ~(IOC4_OTHER_IR_ATA_INT | IOC4_OTHER_IR_ATA_MEMERR), | 2722 | write_ireg(soft, IOC4_OTHER_IR_SER_MEMERR, IOC4_W_IEC, |
2790 | IOC4_W_IEC, IOC4_OTHER_INTR_TYPE); | 2723 | IOC4_OTHER_INTR_TYPE); |
2791 | writel(~(IOC4_OTHER_IR_ATA_MEMERR | IOC4_OTHER_IR_ATA_MEMERR), | 2724 | writel(IOC4_OTHER_IR_SER_MEMERR, &idd->idd_misc_regs->other_ir.raw); |
2792 | &mem->other_ir); | ||
2793 | control->ic_soft = soft; | 2725 | control->ic_soft = soft; |
2794 | if (!request_irq(pdev->irq, ioc4_intr, SA_SHIRQ, | 2726 | |
2727 | /* Hook up interrupt handler */ | ||
2728 | if (!request_irq(idd->idd_pdev->irq, ioc4_intr, SA_SHIRQ, | ||
2795 | "sgi-ioc4serial", (void *)soft)) { | 2729 | "sgi-ioc4serial", (void *)soft)) { |
2796 | control->ic_irq = pdev->irq; | 2730 | control->ic_irq = idd->idd_pdev->irq; |
2797 | } else { | 2731 | } else { |
2798 | printk(KERN_WARNING | 2732 | printk(KERN_WARNING |
2799 | "%s : request_irq fails for IRQ 0x%x\n ", | 2733 | "%s : request_irq fails for IRQ 0x%x\n ", |
2800 | __FUNCTION__, pdev->irq); | 2734 | __FUNCTION__, idd->idd_pdev->irq); |
2801 | } | 2735 | } |
2802 | if ((ret = ioc4_attach_local(pdev, control, soft, | 2736 | if ((ret = ioc4_attach_local(idd->idd_pdev, control, soft, |
2803 | soft->is_ioc4_mem_addr, | 2737 | soft->is_ioc4_misc_addr, |
2804 | soft->is_ioc4_serial_addr))) | 2738 | soft->is_ioc4_serial_addr))) |
2805 | goto out4; | 2739 | goto out4; |
2806 | 2740 | ||
2807 | /* register port with the serial core */ | 2741 | /* register port with the serial core */ |
2808 | 2742 | ||
2809 | if ((ret = ioc4_serial_core_attach(pdev))) | 2743 | if ((ret = ioc4_serial_core_attach(idd->idd_pdev))) |
2810 | goto out4; | 2744 | goto out4; |
2811 | 2745 | ||
2812 | return ret; | 2746 | return ret; |
@@ -2819,7 +2753,6 @@ out3: | |||
2819 | out2: | 2753 | out2: |
2820 | release_region(tmp_addr1, sizeof(struct ioc4_serial)); | 2754 | release_region(tmp_addr1, sizeof(struct ioc4_serial)); |
2821 | out1: | 2755 | out1: |
2822 | release_region(tmp_addr, sizeof(struct ioc4_mem)); | ||
2823 | 2756 | ||
2824 | return ret; | 2757 | return ret; |
2825 | } | 2758 | } |
@@ -2828,11 +2761,10 @@ out1: | |||
2828 | /** | 2761 | /** |
2829 | * ioc4_serial_remove_one - detach function | 2762 | * ioc4_serial_remove_one - detach function |
2830 | * | 2763 | * |
2831 | * @pdev: handle for this card | 2764 | * @idd: IOC4 master module data for this IOC4 |
2832 | */ | 2765 | */ |
2833 | 2766 | ||
2834 | #if 0 | 2767 | int ioc4_serial_remove_one(struct ioc4_driver_data *idd) |
2835 | void ioc4_serial_remove_one(struct pci_dev *pdev) | ||
2836 | { | 2768 | { |
2837 | int ii; | 2769 | int ii; |
2838 | struct ioc4_control *control; | 2770 | struct ioc4_control *control; |
@@ -2840,7 +2772,7 @@ void ioc4_serial_remove_one(struct pci_dev *pdev) | |||
2840 | struct ioc4_port *port; | 2772 | struct ioc4_port *port; |
2841 | struct ioc4_soft *soft; | 2773 | struct ioc4_soft *soft; |
2842 | 2774 | ||
2843 | control = pci_get_drvdata(pdev); | 2775 | control = idd->idd_serial_data; |
2844 | 2776 | ||
2845 | for (ii = 0; ii < IOC4_NUM_SERIAL_PORTS; ii++) { | 2777 | for (ii = 0; ii < IOC4_NUM_SERIAL_PORTS; ii++) { |
2846 | the_port = &control->ic_port[ii].icp_uart_port; | 2778 | the_port = &control->ic_port[ii].icp_uart_port; |
@@ -2867,10 +2799,17 @@ void ioc4_serial_remove_one(struct pci_dev *pdev) | |||
2867 | kfree(soft); | 2799 | kfree(soft); |
2868 | } | 2800 | } |
2869 | kfree(control); | 2801 | kfree(control); |
2870 | pci_set_drvdata(pdev, NULL); | 2802 | idd->idd_serial_data = NULL; |
2871 | uart_unregister_driver(&ioc4_uart); | 2803 | |
2804 | return 0; | ||
2872 | } | 2805 | } |
2873 | #endif | 2806 | |
2807 | static struct ioc4_submodule ioc4_serial_submodule = { | ||
2808 | .is_name = "IOC4_serial", | ||
2809 | .is_owner = THIS_MODULE, | ||
2810 | .is_probe = ioc4_serial_attach_one, | ||
2811 | .is_remove = ioc4_serial_remove_one, | ||
2812 | }; | ||
2874 | 2813 | ||
2875 | /** | 2814 | /** |
2876 | * ioc4_serial_init - module init | 2815 | * ioc4_serial_init - module init |
@@ -2886,12 +2825,20 @@ int ioc4_serial_init(void) | |||
2886 | __FUNCTION__); | 2825 | __FUNCTION__); |
2887 | return ret; | 2826 | return ret; |
2888 | } | 2827 | } |
2889 | return 0; | 2828 | |
2829 | /* register with IOC4 main module */ | ||
2830 | return ioc4_register_submodule(&ioc4_serial_submodule); | ||
2890 | } | 2831 | } |
2891 | 2832 | ||
2833 | static void __devexit ioc4_serial_exit(void) | ||
2834 | { | ||
2835 | ioc4_unregister_submodule(&ioc4_serial_submodule); | ||
2836 | uart_unregister_driver(&ioc4_uart); | ||
2837 | } | ||
2838 | |||
2839 | module_init(ioc4_serial_init); | ||
2840 | module_exit(ioc4_serial_exit); | ||
2841 | |||
2892 | MODULE_AUTHOR("Pat Gefre - Silicon Graphics Inc. (SGI) <pfg@sgi.com>"); | 2842 | MODULE_AUTHOR("Pat Gefre - Silicon Graphics Inc. (SGI) <pfg@sgi.com>"); |
2893 | MODULE_DESCRIPTION("Serial PCI driver module for SGI IOC4 Base-IO Card"); | 2843 | MODULE_DESCRIPTION("Serial PCI driver module for SGI IOC4 Base-IO Card"); |
2894 | MODULE_LICENSE("GPL"); | 2844 | MODULE_LICENSE("GPL"); |
2895 | |||
2896 | EXPORT_SYMBOL(ioc4_serial_init); | ||
2897 | EXPORT_SYMBOL(ioc4_serial_attach_one); | ||
diff --git a/drivers/sn/ioc4.c b/drivers/sn/ioc4.c index d9e4ee280e5f..70862d72ea9d 100644 --- a/drivers/sn/ioc4.c +++ b/drivers/sn/ioc4.c | |||
@@ -6,60 +6,294 @@ | |||
6 | * Copyright (C) 2005 Silicon Graphics, Inc. All Rights Reserved. | 6 | * Copyright (C) 2005 Silicon Graphics, Inc. All Rights Reserved. |
7 | */ | 7 | */ |
8 | 8 | ||
9 | /* | 9 | /* This file contains the master driver module for use by SGI IOC4 subdrivers. |
10 | * This file contains a shim driver for the IOC4 IDE and serial drivers. | 10 | * |
11 | * It allocates any resources shared between multiple subdevices, and | ||
12 | * provides accessor functions (where needed) and the like for those | ||
13 | * resources. It also provides a mechanism for the subdevice modules | ||
14 | * to support loading and unloading. | ||
15 | * | ||
16 | * Non-shared resources (e.g. external interrupt A_INT_OUT register page | ||
17 | * alias, serial port and UART registers) are handled by the subdevice | ||
18 | * modules themselves. | ||
19 | * | ||
20 | * This is all necessary because IOC4 is not implemented as a multi-function | ||
21 | * PCI device, but an amalgamation of disparate registers for several | ||
22 | * types of device (ATA, serial, external interrupts). The normal | ||
23 | * resource management in the kernel doesn't have quite the right interfaces | ||
24 | * to handle this situation (e.g. multiple modules can't claim the same | ||
25 | * PCI ID), thus this IOC4 master module. | ||
11 | */ | 26 | */ |
12 | 27 | ||
13 | #include <linux/errno.h> | 28 | #include <linux/errno.h> |
14 | #include <linux/module.h> | 29 | #include <linux/module.h> |
15 | #include <linux/pci.h> | 30 | #include <linux/pci.h> |
16 | #include <linux/ioc4_common.h> | 31 | #include <linux/ioc4.h> |
17 | #include <linux/ide.h> | 32 | #include <linux/rwsem.h> |
18 | 33 | ||
34 | /************************ | ||
35 | * Submodule management * | ||
36 | ************************/ | ||
19 | 37 | ||
20 | static int __devinit | 38 | static LIST_HEAD(ioc4_devices); |
21 | ioc4_probe_one(struct pci_dev *pdev, const struct pci_device_id *pci_id) | 39 | static DECLARE_RWSEM(ioc4_devices_rwsem); |
40 | |||
41 | static LIST_HEAD(ioc4_submodules); | ||
42 | static DECLARE_RWSEM(ioc4_submodules_rwsem); | ||
43 | |||
44 | /* Register an IOC4 submodule */ | ||
45 | int | ||
46 | ioc4_register_submodule(struct ioc4_submodule *is) | ||
47 | { | ||
48 | struct ioc4_driver_data *idd; | ||
49 | |||
50 | down_write(&ioc4_submodules_rwsem); | ||
51 | list_add(&is->is_list, &ioc4_submodules); | ||
52 | up_write(&ioc4_submodules_rwsem); | ||
53 | |||
54 | /* Initialize submodule for each IOC4 */ | ||
55 | if (!is->is_probe) | ||
56 | return 0; | ||
57 | |||
58 | down_read(&ioc4_devices_rwsem); | ||
59 | list_for_each_entry(idd, &ioc4_devices, idd_list) { | ||
60 | if (is->is_probe(idd)) { | ||
61 | printk(KERN_WARNING | ||
62 | "%s: IOC4 submodule %s probe failed " | ||
63 | "for pci_dev %s", | ||
64 | __FUNCTION__, module_name(is->is_owner), | ||
65 | pci_name(idd->idd_pdev)); | ||
66 | } | ||
67 | } | ||
68 | up_read(&ioc4_devices_rwsem); | ||
69 | |||
70 | return 0; | ||
71 | } | ||
72 | |||
73 | /* Unregister an IOC4 submodule */ | ||
74 | void | ||
75 | ioc4_unregister_submodule(struct ioc4_submodule *is) | ||
22 | { | 76 | { |
77 | struct ioc4_driver_data *idd; | ||
78 | |||
79 | down_write(&ioc4_submodules_rwsem); | ||
80 | list_del(&is->is_list); | ||
81 | up_write(&ioc4_submodules_rwsem); | ||
82 | |||
83 | /* Remove submodule for each IOC4 */ | ||
84 | if (!is->is_remove) | ||
85 | return; | ||
86 | |||
87 | down_read(&ioc4_devices_rwsem); | ||
88 | list_for_each_entry(idd, &ioc4_devices, idd_list) { | ||
89 | if (is->is_remove(idd)) { | ||
90 | printk(KERN_WARNING | ||
91 | "%s: IOC4 submodule %s remove failed " | ||
92 | "for pci_dev %s.\n", | ||
93 | __FUNCTION__, module_name(is->is_owner), | ||
94 | pci_name(idd->idd_pdev)); | ||
95 | } | ||
96 | } | ||
97 | up_read(&ioc4_devices_rwsem); | ||
98 | } | ||
99 | |||
100 | /********************* | ||
101 | * Device management * | ||
102 | *********************/ | ||
103 | |||
104 | /* Adds a new instance of an IOC4 card */ | ||
105 | static int | ||
106 | ioc4_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) | ||
107 | { | ||
108 | struct ioc4_driver_data *idd; | ||
109 | struct ioc4_submodule *is; | ||
110 | uint32_t pcmd; | ||
23 | int ret; | 111 | int ret; |
24 | 112 | ||
113 | /* Enable IOC4 and take ownership of it */ | ||
25 | if ((ret = pci_enable_device(pdev))) { | 114 | if ((ret = pci_enable_device(pdev))) { |
26 | printk(KERN_WARNING | 115 | printk(KERN_WARNING |
27 | "%s: Failed to enable device with " | 116 | "%s: Failed to enable IOC4 device for pci_dev %s.\n", |
28 | "pci_dev 0x%p... returning\n", | 117 | __FUNCTION__, pci_name(pdev)); |
29 | __FUNCTION__, (void *)pdev); | 118 | goto out; |
30 | return ret; | ||
31 | } | 119 | } |
32 | pci_set_master(pdev); | 120 | pci_set_master(pdev); |
33 | 121 | ||
34 | /* attach each sub-device */ | 122 | /* Set up per-IOC4 data */ |
35 | ret = ioc4_ide_attach_one(pdev, pci_id); | 123 | idd = kmalloc(sizeof(struct ioc4_driver_data), GFP_KERNEL); |
36 | if (ret) | 124 | if (!idd) { |
37 | return ret; | 125 | printk(KERN_WARNING |
38 | return ioc4_serial_attach_one(pdev, pci_id); | 126 | "%s: Failed to allocate IOC4 data for pci_dev %s.\n", |
127 | __FUNCTION__, pci_name(pdev)); | ||
128 | ret = -ENODEV; | ||
129 | goto out_idd; | ||
130 | } | ||
131 | idd->idd_pdev = pdev; | ||
132 | idd->idd_pci_id = pci_id; | ||
133 | |||
134 | /* Map IOC4 misc registers. These are shared between subdevices | ||
135 | * so the main IOC4 module manages them. | ||
136 | */ | ||
137 | idd->idd_bar0 = pci_resource_start(idd->idd_pdev, 0); | ||
138 | if (!idd->idd_bar0) { | ||
139 | printk(KERN_WARNING | ||
140 | "%s: Unable to find IOC4 misc resource " | ||
141 | "for pci_dev %s.\n", | ||
142 | __FUNCTION__, pci_name(idd->idd_pdev)); | ||
143 | ret = -ENODEV; | ||
144 | goto out_pci; | ||
145 | } | ||
146 | if (!request_region(idd->idd_bar0, sizeof(struct ioc4_misc_regs), | ||
147 | "ioc4_misc")) { | ||
148 | printk(KERN_WARNING | ||
149 | "%s: Unable to request IOC4 misc region " | ||
150 | "for pci_dev %s.\n", | ||
151 | __FUNCTION__, pci_name(idd->idd_pdev)); | ||
152 | ret = -ENODEV; | ||
153 | goto out_pci; | ||
154 | } | ||
155 | idd->idd_misc_regs = ioremap(idd->idd_bar0, | ||
156 | sizeof(struct ioc4_misc_regs)); | ||
157 | if (!idd->idd_misc_regs) { | ||
158 | printk(KERN_WARNING | ||
159 | "%s: Unable to remap IOC4 misc region " | ||
160 | "for pci_dev %s.\n", | ||
161 | __FUNCTION__, pci_name(idd->idd_pdev)); | ||
162 | ret = -ENODEV; | ||
163 | goto out_misc_region; | ||
164 | } | ||
165 | |||
166 | /* Failsafe portion of per-IOC4 initialization */ | ||
167 | |||
168 | /* Initialize IOC4 */ | ||
169 | pci_read_config_dword(idd->idd_pdev, PCI_COMMAND, &pcmd); | ||
170 | pci_write_config_dword(idd->idd_pdev, PCI_COMMAND, | ||
171 | pcmd | PCI_COMMAND_PARITY | PCI_COMMAND_SERR); | ||
172 | |||
173 | /* Disable/clear all interrupts. Need to do this here lest | ||
174 | * one submodule request the shared IOC4 IRQ, but interrupt | ||
175 | * is generated by a different subdevice. | ||
176 | */ | ||
177 | /* Disable */ | ||
178 | writel(~0, &idd->idd_misc_regs->other_iec.raw); | ||
179 | writel(~0, &idd->idd_misc_regs->sio_iec); | ||
180 | /* Clear (i.e. acknowledge) */ | ||
181 | writel(~0, &idd->idd_misc_regs->other_ir.raw); | ||
182 | writel(~0, &idd->idd_misc_regs->sio_ir); | ||
183 | |||
184 | /* Track PCI-device specific data */ | ||
185 | idd->idd_serial_data = NULL; | ||
186 | pci_set_drvdata(idd->idd_pdev, idd); | ||
187 | down_write(&ioc4_devices_rwsem); | ||
188 | list_add(&idd->idd_list, &ioc4_devices); | ||
189 | up_write(&ioc4_devices_rwsem); | ||
190 | |||
191 | /* Add this IOC4 to all submodules */ | ||
192 | down_read(&ioc4_submodules_rwsem); | ||
193 | list_for_each_entry(is, &ioc4_submodules, is_list) { | ||
194 | if (is->is_probe && is->is_probe(idd)) { | ||
195 | printk(KERN_WARNING | ||
196 | "%s: IOC4 submodule 0x%s probe failed " | ||
197 | "for pci_dev %s.\n", | ||
198 | __FUNCTION__, module_name(is->is_owner), | ||
199 | pci_name(idd->idd_pdev)); | ||
200 | } | ||
201 | } | ||
202 | up_read(&ioc4_submodules_rwsem); | ||
203 | |||
204 | return 0; | ||
205 | |||
206 | out_misc_region: | ||
207 | release_region(idd->idd_bar0, sizeof(struct ioc4_misc_regs)); | ||
208 | out_pci: | ||
209 | kfree(idd); | ||
210 | out_idd: | ||
211 | pci_disable_device(pdev); | ||
212 | out: | ||
213 | return ret; | ||
39 | } | 214 | } |
40 | 215 | ||
41 | /* pci device struct */ | 216 | /* Removes a particular instance of an IOC4 card. */ |
42 | static struct pci_device_id ioc4_s_id_table[] = { | 217 | static void |
218 | ioc4_remove(struct pci_dev *pdev) | ||
219 | { | ||
220 | struct ioc4_submodule *is; | ||
221 | struct ioc4_driver_data *idd; | ||
222 | |||
223 | idd = pci_get_drvdata(pdev); | ||
224 | |||
225 | /* Remove this IOC4 from all submodules */ | ||
226 | down_read(&ioc4_submodules_rwsem); | ||
227 | list_for_each_entry(is, &ioc4_submodules, is_list) { | ||
228 | if (is->is_remove && is->is_remove(idd)) { | ||
229 | printk(KERN_WARNING | ||
230 | "%s: IOC4 submodule 0x%s remove failed " | ||
231 | "for pci_dev %s.\n", | ||
232 | __FUNCTION__, module_name(is->is_owner), | ||
233 | pci_name(idd->idd_pdev)); | ||
234 | } | ||
235 | } | ||
236 | up_read(&ioc4_submodules_rwsem); | ||
237 | |||
238 | /* Release resources */ | ||
239 | iounmap(idd->idd_misc_regs); | ||
240 | if (!idd->idd_bar0) { | ||
241 | printk(KERN_WARNING | ||
242 | "%s: Unable to get IOC4 misc mapping for pci_dev %s. " | ||
243 | "Device removal may be incomplete.\n", | ||
244 | __FUNCTION__, pci_name(idd->idd_pdev)); | ||
245 | } | ||
246 | release_region(idd->idd_bar0, sizeof(struct ioc4_misc_regs)); | ||
247 | |||
248 | /* Disable IOC4 and relinquish */ | ||
249 | pci_disable_device(pdev); | ||
250 | |||
251 | /* Remove and free driver data */ | ||
252 | down_write(&ioc4_devices_rwsem); | ||
253 | list_del(&idd->idd_list); | ||
254 | up_write(&ioc4_devices_rwsem); | ||
255 | kfree(idd); | ||
256 | } | ||
257 | |||
258 | static struct pci_device_id ioc4_id_table[] = { | ||
43 | {PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC4, PCI_ANY_ID, | 259 | {PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC4, PCI_ANY_ID, |
44 | PCI_ANY_ID, 0x0b4000, 0xFFFFFF}, | 260 | PCI_ANY_ID, 0x0b4000, 0xFFFFFF}, |
45 | {0} | 261 | {0} |
46 | }; | 262 | }; |
47 | MODULE_DEVICE_TABLE(pci, ioc4_s_id_table); | ||
48 | 263 | ||
49 | static struct pci_driver __devinitdata ioc4_s_driver = { | 264 | static struct pci_driver __devinitdata ioc4_driver = { |
50 | .name = "IOC4", | 265 | .name = "IOC4", |
51 | .id_table = ioc4_s_id_table, | 266 | .id_table = ioc4_id_table, |
52 | .probe = ioc4_probe_one, | 267 | .probe = ioc4_probe, |
268 | .remove = ioc4_remove, | ||
53 | }; | 269 | }; |
54 | 270 | ||
55 | static int __devinit ioc4_detect(void) | 271 | MODULE_DEVICE_TABLE(pci, ioc4_id_table); |
272 | |||
273 | /********************* | ||
274 | * Module management * | ||
275 | *********************/ | ||
276 | |||
277 | /* Module load */ | ||
278 | static int __devinit | ||
279 | ioc4_init(void) | ||
56 | { | 280 | { |
57 | ioc4_serial_init(); | 281 | return pci_register_driver(&ioc4_driver); |
282 | } | ||
58 | 283 | ||
59 | return pci_register_driver(&ioc4_s_driver); | 284 | /* Module unload */ |
285 | static void __devexit | ||
286 | ioc4_exit(void) | ||
287 | { | ||
288 | pci_unregister_driver(&ioc4_driver); | ||
60 | } | 289 | } |
61 | module_init(ioc4_detect); | ||
62 | 290 | ||
63 | MODULE_AUTHOR("Pat Gefre - Silicon Graphics Inc. (SGI) <pfg@sgi.com>"); | 291 | module_init(ioc4_init); |
64 | MODULE_DESCRIPTION("PCI driver module for SGI IOC4 Base-IO Card"); | 292 | module_exit(ioc4_exit); |
293 | |||
294 | MODULE_AUTHOR("Brent Casavant - Silicon Graphics, Inc. <bcasavan@sgi.com>"); | ||
295 | MODULE_DESCRIPTION("PCI driver master module for SGI IOC4 Base-IO Card"); | ||
65 | MODULE_LICENSE("GPL"); | 296 | MODULE_LICENSE("GPL"); |
297 | |||
298 | EXPORT_SYMBOL(ioc4_register_submodule); | ||
299 | EXPORT_SYMBOL(ioc4_unregister_submodule); | ||