linux-mips
[Top] [All Lists]

[PATCH] Make drivers/sn/ioc3.c usable on Mips

To: linux-mips@linux-mips.org, kumba@gentoo.org
Subject: [PATCH] Make drivers/sn/ioc3.c usable on Mips
From: Johannes Dickgreber <tanzy@gmx.de>
Date: Tue, 16 Oct 2007 20:16:47 +0200
Cc: Johannes Dickgreber <tanzy@gmx.de>
Original-recipient: rfc822;linux-mips@linux-mips.org
Sender: linux-mips-bounce@linux-mips.org
This makes driver/sn/ioc3.c usable on Mips.

Changes:
        make ethernet subdriver use always slot 0
        changes in test for dual_irq, test active[] first

Only tested on SGI Octane which is out of tree.
Please test on other Arch and machines.
---
 drivers/Makefile     |    2 +-
 drivers/sn/Kconfig   |    6 +--
 drivers/sn/ioc3.c    |  121 ++++++++++++++++++++++++++++++--------------------
 include/linux/ioc3.h |    2 +
 4 files changed, 77 insertions(+), 54 deletions(-)

diff --git a/drivers/Makefile b/drivers/Makefile
index f0878b2..c8dba0c 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -79,7 +79,7 @@ obj-$(CONFIG_CPU_FREQ)                += cpufreq/
 obj-$(CONFIG_MMC)              += mmc/
 obj-$(CONFIG_NEW_LEDS)         += leds/
 obj-$(CONFIG_INFINIBAND)       += infiniband/
-obj-$(CONFIG_SGI_SN)           += sn/
+obj-$(CONFIG_SGI_IOC3)         += sn/
 obj-y                          += firmware/
 obj-$(CONFIG_CRYPTO)           += crypto/
 obj-$(CONFIG_SUPERH)           += sh/
diff --git a/drivers/sn/Kconfig b/drivers/sn/Kconfig
index c66ba9a..3649ad1 100644
--- a/drivers/sn/Kconfig
+++ b/drivers/sn/Kconfig
@@ -2,11 +2,9 @@
 # Miscellaneous SN-specific devices
 #
 
-menu "SN Devices"
-       depends on SGI_SN
-
 config SGI_IOC3
        tristate "SGI IOC3 Base IO support"
+       depends on PCI && (SGI_SN || SGI_IP30)
        default m
        ---help---
        This option enables basic support for the SGI IOC3-based Base IO
@@ -17,5 +15,3 @@ config SGI_IOC3
        If you have an SGI Altix with an IOC3-based
        I/O controller or a PCI IOC3 serial card say Y.
        Otherwise say N.
-
-endmenu
diff --git a/drivers/sn/ioc3.c b/drivers/sn/ioc3.c
index 29fcd6d..c66c866 100644
--- a/drivers/sn/ioc3.c
+++ b/drivers/sn/ioc3.c
@@ -23,8 +23,9 @@ static LIST_HEAD(ioc3_devices);
 static int ioc3_counter;
 static DECLARE_RWSEM(ioc3_devices_rwsem);
 
+/* ethernet submodule is always 0 */
+#define ETH_ID 0
 static struct ioc3_submodule *ioc3_submodules[IOC3_MAX_SUBMODULES];
-static struct ioc3_submodule *ioc3_ethernet;
 static DEFINE_RWLOCK(ioc3_submodules_lock);
 
 /* NIC probing code */
@@ -293,11 +294,13 @@ static void read_nic(struct ioc3_driver_data *idd, 
unsigned long addr)
                if(data[i+32] != ' ')
                        part[j++] = data[i+32];
        part[j] = 0;
-       /* skip Octane power supplies */
-       if(!strncmp(part, "060-0035-", 9))
-               return;
-       if(!strncmp(part, "060-0038-", 9))
+
+       /* skip Octane (IP30) power supplies */
+       if (!(strncmp(part, "060-0035-", 9)) ||
+           !(strncmp(part, "060-0038-", 9)) ||
+           !(strncmp(part, "060-0028-", 9)))
                return;
+
        strcpy(idd->nic_part, part);
        /* assemble the serial # */
        j=0;
@@ -406,32 +409,36 @@ static irqreturn_t ioc3_intr_io(int irq, void *arg)
        unsigned int pending;
 
        read_lock_irqsave(&ioc3_submodules_lock, flags);
-
-       if(idd->dual_irq && readb(&idd->vma->eisr)) {
-               /* send Ethernet IRQ to the driver */
-               if(ioc3_ethernet && idd->active[ioc3_ethernet->id] &&
-                                               ioc3_ethernet->intr) {
-                       handled = handled && !ioc3_ethernet->intr(ioc3_ethernet,
-                                                       idd, 0);
-               }
-       }
-       pending = get_pending_intrs(idd);       /* look at the IO IRQs */
-
-       for(id=0;id<IOC3_MAX_SUBMODULES;id++) {
-               if(idd->active[id] && ioc3_submodules[id]
-                               && (pending & ioc3_submodules[id]->irq_mask)
-                               && ioc3_submodules[id]->intr) {
-                       write_ireg(idd, ioc3_submodules[id]->irq_mask,
-                                                       IOC3_W_IEC);
-                       if(!ioc3_submodules[id]->intr(ioc3_submodules[id],
-                                  idd, pending & 
ioc3_submodules[id]->irq_mask))
-                               pending &= ~ioc3_submodules[id]->irq_mask;
-                       if (ioc3_submodules[id]->reset_mask)
-                               write_ireg(idd, ioc3_submodules[id]->irq_mask,
-                                                       IOC3_W_IES);
+       /* send Ethernet IRQ to the driver */
+       if (idd->active[ETH_ID] && !idd->dual_irq)
+               if (readl(&idd->vma->eisr))
+                       handled = !ioc3_submodules[ETH_ID]->
+                                   intr(ioc3_submodules[ETH_ID], idd, 0);
+
+       /* look at the IO IRQs */
+       pending = get_pending_intrs(idd);
+       for (id = 1; id < IOC3_MAX_SUBMODULES; id++)
+               if (idd->active[id]) &&
+                   (pending & ioc3_submodules[id]->irq_mask)
+                   {
+                               write_ireg(idd, ioc3_submodules[id]->
+                                       irq_mask, IOC3_W_IEC);
+                               if (!ioc3_submodules[id]->
+                                       intr(ioc3_submodules[id], idd,
+                                               (pending &
+                                               ioc3_submodules[id]->irq_mask)))
+                                       {
+                                       pending &= ~ioc3_submodules[id]->
+                                                   irq_mask;
+                                       handled = 1;
+                               }
+                               if (ioc3_submodules[id]->reset_mask)
+                                       write_ireg(idd,
+                                               ioc3_submodules[id]->irq_mask,
+                                               IOC3_W_IES);
                }
-       }
        read_unlock_irqrestore(&ioc3_submodules_lock, flags);
+
        if(pending) {
                printk(KERN_WARNING
                  "IOC3: Pending IRQs 0x%08x discarded and disabled\n",pending);
@@ -445,15 +452,13 @@ static irqreturn_t ioc3_intr_eth(int irq, void *arg)
 {
        unsigned long flags;
        struct ioc3_driver_data *idd = (struct ioc3_driver_data *)arg;
-       int handled = 1;
+       int handled = 0;
 
-       if(!idd->dual_irq)
-               return IRQ_NONE;
        read_lock_irqsave(&ioc3_submodules_lock, flags);
-       if(ioc3_ethernet && idd->active[ioc3_ethernet->id]
-                               && ioc3_ethernet->intr)
-               handled = handled && !ioc3_ethernet->intr(ioc3_ethernet, idd, 
0);
+       if (idd->active[ETH_ID] && idd->dual_irq)
+               handled = 
!ioc3_submodules[ETH_ID]->intr(ioc3_submodules[ETH_ID], idd, 0);
        read_unlock_irqrestore(&ioc3_submodules_lock, flags);
+
        return handled?IRQ_HANDLED:IRQ_NONE;
 }
 
@@ -475,6 +480,7 @@ void ioc3_disable(struct ioc3_submodule *is,
        write_ireg(idd, irqs & is->irq_mask, IOC3_W_IEC);
 }
 
+/* SGI SN2 writes to gpcr to set GPIOs to output */
 void ioc3_gpcr_set(struct ioc3_driver_data *idd, unsigned int val)
 {
        unsigned long flags;
@@ -483,11 +489,23 @@ void ioc3_gpcr_set(struct ioc3_driver_data *idd, unsigned 
int val)
        spin_unlock_irqrestore(&idd->gpio_lock, flags);
 }
 
+/* IP27, IP30 writes to gpdr to set GPIOs to 1 */
+void ioc3_gpio(struct ioc3_driver_data *idd, unsigned int mask, unsigned int 
val)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&idd->gpio_lock, flags);
+       idd->gpdr_shadow &= ~mask;
+       idd->gpdr_shadow |= (val & mask);
+       writel(idd->gpdr_shadow, &idd->vma->gpdr);
+       spin_unlock_irqrestore(&idd->gpio_lock, flags);
+}
+
 /* Keep it simple, stupid! */
 static int find_slot(void **tab, int max)
 {
        int i;
-       for(i=0;i<max;i++)
+       for(i=1;i<max;i++)
                if(!(tab[i]))
                        return i;
        return -1;
@@ -501,17 +519,16 @@ int ioc3_register_submodule(struct ioc3_submodule *is)
        unsigned long flags;
 
        write_lock_irqsave(&ioc3_submodules_lock, flags);
-       alloc_id = find_slot((void **)ioc3_submodules, IOC3_MAX_SUBMODULES);
-       if(alloc_id != -1) {
+       if (is->ethernet)
+               if (ioc3_submodules[ETH_ID] == NULL)
+                       alloc_id = ETH_ID;
+               else
+                       alloc_id = -2;
+       else
+               alloc_id = find_slot((void **)ioc3_submodules, 
IOC3_MAX_SUBMODULES);
+
+       if (alloc_id >= 0)
                ioc3_submodules[alloc_id] = is;
-               if(is->ethernet) {
-                       if(ioc3_ethernet==NULL)
-                               ioc3_ethernet=is;
-                       else
-                               printk(KERN_WARNING
-                                 "IOC3 Ethernet module already registered!\n");
-               }
-       }
        write_unlock_irqrestore(&ioc3_submodules_lock, flags);
 
        if(alloc_id == -1) {
@@ -519,6 +536,11 @@ int ioc3_register_submodule(struct ioc3_submodule *is)
                return -ENOMEM;
        }
 
+       if (alloc_id == -2) {
+               printk(KERN_WARNING "IOC3 Ethernet module already 
registered!\n");
+               return -ENODEV;
+       }
+
        is->id=alloc_id;
 
        /* Initialize submodule for each IOC3 */
@@ -548,8 +570,6 @@ void ioc3_unregister_submodule(struct ioc3_submodule *is)
        else
                printk(KERN_WARNING
                        "IOC3 submodule %s has wrong ID.\n",is->name);
-       if(ioc3_ethernet==is)
-               ioc3_ethernet = NULL;
        write_unlock_irqrestore(&ioc3_submodules_lock, flags);
 
        /* Remove submodule for each IOC3 */
@@ -817,9 +837,13 @@ MODULE_DEVICE_TABLE(pci, ioc3_id_table);
 /* Module load */
 static int __devinit ioc3_init(void)
 {
+#ifdef CONFIG_IA64_SGI_SN2
        if (ia64_platform_is("sn2"))
                return pci_register_driver(&ioc3_driver);
        return 0;
+#else
+       return pci_register_driver(&ioc3_driver);
+#endif
 }
 
 /* Module unload */
@@ -841,3 +865,4 @@ EXPORT_SYMBOL_GPL(ioc3_ack);
 EXPORT_SYMBOL_GPL(ioc3_gpcr_set);
 EXPORT_SYMBOL_GPL(ioc3_disable);
 EXPORT_SYMBOL_GPL(ioc3_enable);
+EXPORT_SYMBOL_GPL(ioc3_gpio);
diff --git a/include/linux/ioc3.h b/include/linux/ioc3.h
index 38b286e..4499243 100644
--- a/include/linux/ioc3.h
+++ b/include/linux/ioc3.h
@@ -89,5 +89,7 @@ extern void ioc3_disable(struct ioc3_submodule *, struct 
ioc3_driver_data *, uns
 extern void ioc3_gpcr_set(struct ioc3_driver_data *, unsigned int);
 /* general ireg writer */
 extern void ioc3_write_ireg(struct ioc3_driver_data *idd, uint32_t value, int 
reg);
+/* atomically sets/clears GPIO bits */
+extern void ioc3_gpio(struct ioc3_driver_data *, unsigned int, unsigned int);
 
 #endif
-- 
1.5.2.5


<Prev in Thread] Current Thread [Next in Thread>
  • [PATCH] Make drivers/sn/ioc3.c usable on Mips, Johannes Dickgreber <=