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 <mb@bu3sch.de> Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
parent
f3dd3fcc2c
commit
993e1c780b
2 changed files with 45 additions and 29 deletions
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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. */
|
||||
|
|
Loading…
Reference in a new issue