linux-wireless.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] ssb: Fix PCMCIA lowlevel register access
@ 2007-12-22 21:01 Michael Buesch
  0 siblings, 0 replies; only message in thread
From: Michael Buesch @ 2007-12-22 21:01 UTC (permalink / raw)
  To: John Linville; +Cc: bcm43xx-dev, linux-wireless

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 <mb@bu3sch.de>

Index: wireless-2.6/drivers/ssb/pcmcia.c
===================================================================
--- wireless-2.6.orig/drivers/ssb/pcmcia.c	2007-12-09 21:33:20.000000000 +0100
+++ wireless-2.6/drivers/ssb/pcmcia.c	2007-12-09 22:16:59.000000000 +0100
@@ -94,7 +94,6 @@ int ssb_pcmcia_switch_core(struct ssb_bu
 			   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_bu
 		   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_bu
 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
 		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(struc
 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_
 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;
 }
 
Index: wireless-2.6/include/linux/ssb/ssb.h
===================================================================
--- wireless-2.6.orig/include/linux/ssb/ssb.h	2007-12-09 22:16:39.000000000 +0100
+++ wireless-2.6/include/linux/ssb/ssb.h	2007-12-09 22:16:59.000000000 +0100
@@ -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. */

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2007-12-22 21:02 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-12-22 21:01 [PATCH] ssb: Fix PCMCIA lowlevel register access Michael Buesch

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).