summaryrefslogtreecommitdiffstats
path: root/target/linux/generic-2.6/files/drivers/ssb/pcmcia.c
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/generic-2.6/files/drivers/ssb/pcmcia.c')
-rw-r--r--target/linux/generic-2.6/files/drivers/ssb/pcmcia.c104
1 files changed, 60 insertions, 44 deletions
diff --git a/target/linux/generic-2.6/files/drivers/ssb/pcmcia.c b/target/linux/generic-2.6/files/drivers/ssb/pcmcia.c
index 7c773603b..46816cda8 100644
--- a/target/linux/generic-2.6/files/drivers/ssb/pcmcia.c
+++ b/target/linux/generic-2.6/files/drivers/ssb/pcmcia.c
@@ -10,6 +10,7 @@
#include <linux/ssb/ssb.h>
#include <linux/delay.h>
+#include <linux/io.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
@@ -62,17 +63,17 @@ int ssb_pcmcia_switch_coreidx(struct ssb_bus *bus,
err = pcmcia_access_configuration_register(pdev, &reg);
if (err != CS_SUCCESS)
goto error;
- read_addr |= (reg.Value & 0xF) << 12;
+ read_addr |= ((u32)(reg.Value & 0x0F)) << 12;
reg.Offset = 0x30;
err = pcmcia_access_configuration_register(pdev, &reg);
if (err != CS_SUCCESS)
goto error;
- read_addr |= reg.Value << 16;
+ read_addr |= ((u32)reg.Value) << 16;
reg.Offset = 0x32;
err = pcmcia_access_configuration_register(pdev, &reg);
if (err != CS_SUCCESS)
goto error;
- read_addr |= reg.Value << 24;
+ read_addr |= ((u32)reg.Value) << 24;
cur_core = (read_addr - SSB_ENUM_BASE) / SSB_CORE_SIZE;
if (cur_core == coreidx)
@@ -93,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
@@ -102,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;
}
@@ -114,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;
@@ -142,37 +138,36 @@ 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;
}
-/* These are the main device register access functions.
- * do_select_core is inline to have the likely hotpath inline.
- * All unlikely codepaths are out-of-line. */
-static inline int do_select_core(struct ssb_bus *bus,
- struct ssb_device *dev,
- u16 *offset)
+static int select_core_and_segment(struct ssb_device *dev,
+ u16 *offset)
{
+ struct ssb_bus *bus = dev->bus;
int err;
- u8 need_seg = (*offset >= 0x800) ? 1 : 0;
+ u8 need_segment;
+
+ if (*offset >= 0x800) {
+ *offset -= 0x800;
+ need_segment = 1;
+ } else
+ need_segment = 0;
if (unlikely(dev != bus->mapped_device)) {
err = ssb_pcmcia_switch_core(bus, dev);
if (unlikely(err))
return err;
}
- if (unlikely(need_seg != bus->mapped_pcmcia_seg)) {
- err = ssb_pcmcia_switch_segment(bus, need_seg);
+ if (unlikely(need_segment != bus->mapped_pcmcia_seg)) {
+ err = ssb_pcmcia_switch_segment(bus, need_segment);
if (unlikely(err))
return err;
}
- if (need_seg == 1)
- *offset -= 0x800;
return 0;
}
@@ -180,46 +175,65 @@ static inline int do_select_core(struct ssb_bus *bus,
static u16 ssb_pcmcia_read16(struct ssb_device *dev, u16 offset)
{
struct ssb_bus *bus = dev->bus;
- u16 x;
+ unsigned long flags;
+ int err;
+ u16 value = 0xFFFF;
- if (unlikely(do_select_core(bus, dev, &offset)))
- return 0xFFFF;
- x = readw(bus->mmio + offset);
+ 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 x;
+ return value;
}
static u32 ssb_pcmcia_read32(struct ssb_device *dev, u16 offset)
{
struct ssb_bus *bus = dev->bus;
- u32 x;
+ unsigned long flags;
+ int err;
+ u32 lo = 0xFFFFFFFF, hi = 0xFFFFFFFF;
- if (unlikely(do_select_core(bus, dev, &offset)))
- return 0xFFFFFFFF;
- x = readl(bus->mmio + offset);
+ 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 x;
+ return (lo | (hi << 16));
}
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(do_select_core(bus, 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(do_select_core(bus, dev, &offset)))
- return;
- readw(bus->mmio + offset);
- writew(value >> 16, bus->mmio + offset + 2);
- readw(bus->mmio + offset);
- writew(value, bus->mmio + offset);
+ 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 */
@@ -230,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;
}