Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=993e1c780b323736a2cdc24564f35e80ce8d3337
Commit:     993e1c780b323736a2cdc24564f35e80ce8d3337
Parent:     f3dd3fcc2c79b950801641075b33b86acc372d9b
Author:     Michael Buesch <[EMAIL PROTECTED]>
AuthorDate: Sat Dec 22 22:01:36 2007 +0100
Committer:  David S. Miller <[EMAIL PROTECTED]>
CommitDate: Mon Jan 28 15:09:16 2008 -0800

    ssb: Fix PCMCIA lowlevel register access
    
    This fixes lowlevel register access for PCMCIA based devices.
    
    The patch also adds a temporary workaround for the device mac address.
    It simply adds generation of a random address. The real SPROM extraction
    will follow in another patch.
    The temporary workaround will be removed then, but for now it's OK.
    
    Signed-off-by: Michael Buesch <[EMAIL PROTECTED]>
    Signed-off-by: John W. Linville <[EMAIL PROTECTED]>
---
 drivers/ssb/pcmcia.c    |   71 ++++++++++++++++++++++++++++------------------
 include/linux/ssb/ssb.h |    3 +-
 2 files changed, 45 insertions(+), 29 deletions(-)

diff --git a/drivers/ssb/pcmcia.c b/drivers/ssb/pcmcia.c
index bb44a76..46816cd 100644
--- a/drivers/ssb/pcmcia.c
+++ b/drivers/ssb/pcmcia.c
@@ -94,7 +94,6 @@ int ssb_pcmcia_switch_core(struct ssb_bus *bus,
                           struct ssb_device *dev)
 {
        int err;
-       unsigned long flags;
 
 #if SSB_VERBOSE_PCMCIACORESWITCH_DEBUG
        ssb_printk(KERN_INFO PFX
@@ -103,11 +102,9 @@ int ssb_pcmcia_switch_core(struct ssb_bus *bus,
                   dev->core_index);
 #endif
 
-       spin_lock_irqsave(&bus->bar_lock, flags);
        err = ssb_pcmcia_switch_coreidx(bus, dev->core_index);
        if (!err)
                bus->mapped_device = dev;
-       spin_unlock_irqrestore(&bus->bar_lock, flags);
 
        return err;
 }
@@ -115,14 +112,12 @@ int ssb_pcmcia_switch_core(struct ssb_bus *bus,
 int ssb_pcmcia_switch_segment(struct ssb_bus *bus, u8 seg)
 {
        int attempts = 0;
-       unsigned long flags;
        conf_reg_t reg;
-       int res, err = 0;
+       int res;
 
        SSB_WARN_ON((seg != 0) && (seg != 1));
        reg.Offset = 0x34;
        reg.Function = 0;
-       spin_lock_irqsave(&bus->bar_lock, flags);
        while (1) {
                reg.Action = CS_WRITE;
                reg.Value = seg;
@@ -143,13 +138,11 @@ int ssb_pcmcia_switch_segment(struct ssb_bus *bus, u8 seg)
                udelay(10);
        }
        bus->mapped_pcmcia_seg = seg;
-out_unlock:
-       spin_unlock_irqrestore(&bus->bar_lock, flags);
-       return err;
+
+       return 0;
 error:
        ssb_printk(KERN_ERR PFX "Failed to switch pcmcia segment\n");
-       err = -ENODEV;
-       goto out_unlock;
+       return -ENODEV;
 }
 
 static int select_core_and_segment(struct ssb_device *dev,
@@ -182,22 +175,33 @@ static int select_core_and_segment(struct ssb_device *dev,
 static u16 ssb_pcmcia_read16(struct ssb_device *dev, u16 offset)
 {
        struct ssb_bus *bus = dev->bus;
+       unsigned long flags;
+       int err;
+       u16 value = 0xFFFF;
 
-       if (unlikely(select_core_and_segment(dev, &offset)))
-               return 0xFFFF;
+       spin_lock_irqsave(&bus->bar_lock, flags);
+       err = select_core_and_segment(dev, &offset);
+       if (likely(!err))
+               value = readw(bus->mmio + offset);
+       spin_unlock_irqrestore(&bus->bar_lock, flags);
 
-       return readw(bus->mmio + offset);
+       return value;
 }
 
 static u32 ssb_pcmcia_read32(struct ssb_device *dev, u16 offset)
 {
        struct ssb_bus *bus = dev->bus;
-       u32 lo, hi;
+       unsigned long flags;
+       int err;
+       u32 lo = 0xFFFFFFFF, hi = 0xFFFFFFFF;
 
-       if (unlikely(select_core_and_segment(dev, &offset)))
-               return 0xFFFFFFFF;
-       lo = readw(bus->mmio + offset);
-       hi = readw(bus->mmio + offset + 2);
+       spin_lock_irqsave(&bus->bar_lock, flags);
+       err = select_core_and_segment(dev, &offset);
+       if (likely(!err)) {
+               lo = readw(bus->mmio + offset);
+               hi = readw(bus->mmio + offset + 2);
+       }
+       spin_unlock_irqrestore(&bus->bar_lock, flags);
 
        return (lo | (hi << 16));
 }
@@ -205,22 +209,31 @@ static u32 ssb_pcmcia_read32(struct ssb_device *dev, u16 
offset)
 static void ssb_pcmcia_write16(struct ssb_device *dev, u16 offset, u16 value)
 {
        struct ssb_bus *bus = dev->bus;
+       unsigned long flags;
+       int err;
 
-       if (unlikely(select_core_and_segment(dev, &offset)))
-               return;
-       writew(value, bus->mmio + offset);
+       spin_lock_irqsave(&bus->bar_lock, flags);
+       err = select_core_and_segment(dev, &offset);
+       if (likely(!err))
+               writew(value, bus->mmio + offset);
+       mmiowb();
+       spin_unlock_irqrestore(&bus->bar_lock, flags);
 }
 
 static void ssb_pcmcia_write32(struct ssb_device *dev, u16 offset, u32 value)
 {
        struct ssb_bus *bus = dev->bus;
+       unsigned long flags;
+       int err;
 
-       if (unlikely(select_core_and_segment(dev, &offset)))
-               return;
-       writeb((value & 0xFF000000) >> 24, bus->mmio + offset + 3);
-       writeb((value & 0x00FF0000) >> 16, bus->mmio + offset + 2);
-       writeb((value & 0x0000FF00) >> 8, bus->mmio + offset + 1);
-       writeb((value & 0x000000FF) >> 0, bus->mmio + offset + 0);
+       spin_lock_irqsave(&bus->bar_lock, flags);
+       err = select_core_and_segment(dev, &offset);
+       if (likely(!err)) {
+               writew((value & 0x0000FFFF), bus->mmio + offset);
+               writew(((value & 0xFFFF0000) >> 16), bus->mmio + offset + 2);
+       }
+       mmiowb();
+       spin_unlock_irqrestore(&bus->bar_lock, flags);
 }
 
 /* Not "static", as it's used in main.c */
@@ -231,10 +244,12 @@ const struct ssb_bus_ops ssb_pcmcia_ops = {
        .write32        = ssb_pcmcia_write32,
 };
 
+#include <linux/etherdevice.h>
 int ssb_pcmcia_get_invariants(struct ssb_bus *bus,
                              struct ssb_init_invariants *iv)
 {
        //TODO
+       random_ether_addr(iv->sprom.il0mac);
        return 0;
 }
 
diff --git a/include/linux/ssb/ssb.h b/include/linux/ssb/ssb.h
index 0eaa984..cacbae5 100644
--- a/include/linux/ssb/ssb.h
+++ b/include/linux/ssb/ssb.h
@@ -231,7 +231,8 @@ struct ssb_bus {
        struct ssb_device *mapped_device;
        /* Currently mapped PCMCIA segment. (bustype == SSB_BUSTYPE_PCMCIA 
only) */
        u8 mapped_pcmcia_seg;
-       /* Lock for core and segment switching. */
+       /* Lock for core and segment switching.
+        * On PCMCIA-host busses this is used to protect the whole MMIO access. 
*/
        spinlock_t bar_lock;
 
        /* The bus this backplane is running on. */
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to