[OpenBIOS] [PATCH] Fix up LANCE ethernet DMA mapping under Solaris 8 on SPARC32.

Mark Cave-Ayland mark.cave-ayland at siriusit.co.uk
Mon Apr 25 18:48:24 CEST 2011


It seems that Solaris doesn't set up a DMA mapping for the LANCE DMA buffers
and hence must inherit this from OpenBIOS. To make things more complicated,
Solaris appears to assume that the buffers are fixed at 0xff000000 rather
than detecting this information from the OpenBIOS IOMMU pagetable before
switching. Mimicking this behaviour with a fixed location allows Solaris
8 to correctly use the network card under QEMU.

Signed-off-by: Mark Cave-Ayland <mark.cave-ayland at siriusit.co.uk>
---
 openbios-devel/drivers/sbus.c |   55 ++++++++++++++++++++++++++++++++++++++--
 1 files changed, 52 insertions(+), 3 deletions(-)

diff --git a/openbios-devel/drivers/sbus.c b/openbios-devel/drivers/sbus.c
index f4a6d66..1107c1d 100644
--- a/openbios-devel/drivers/sbus.c
+++ b/openbios-devel/drivers/sbus.c
@@ -29,6 +29,20 @@
 #define SS600MP_ESPDMA   0x00081000ULL
 #define SS600MP_ESP      0x00080000ULL
 #define SS600MP_LEBUFFER (SS600MP_ESPDMA + 0x10) // XXX should be 0x40000
+#define LEDMA_REGS       0x4
+#define LE_REGS          0x20
+
+#ifdef CONFIG_DEBUG_SBUS
+#define DPRINTF(fmt, args...)                   \
+    do { printk(fmt , ##args); } while (0)
+#else
+#define DPRINTF(fmt, args...)
+#endif
+
+typedef struct le_private {
+    uint32_t *dmaregs;
+    uint32_t *regs;
+} le_private_t;
 
 static void
 ob_sbus_node_init(uint64_t base)
@@ -57,8 +71,36 @@ ob_sbus_node_init(uint64_t base)
 }
 
 static void
-ob_le_init(unsigned int slot, unsigned long leoffset, unsigned long dmaoffset)
+ob_le_init(unsigned int slot, uint64_t base, unsigned long leoffset, unsigned long dmaoffset)
 {
+    le_private_t *le;
+
+    le = malloc(sizeof(le_private_t));
+    if (!le) {
+        DPRINTF("Can't allocate LANCE private structure\n");
+        return;
+    }
+
+    /* Get the IO region for DMA registers */
+    le->dmaregs = (void *)ofmem_map_io(base + (uint64_t)dmaoffset, LEDMA_REGS);
+    if (le->dmaregs == NULL) {
+        DPRINTF("Can't map LANCE DMA registers\n");
+        return;
+    }
+
+    /* Now it appears that the Solaris kernel forgets to set up the LANCE DMA mapping
+       and so it must inherit the one from OpenBIOS. The symptom of this is that the
+       LANCE DMA base addr register is still zero, and so we start sending network 
+       packets containing random areas of memory.
+       
+       The correct fix for this should be to use dvma_alloc() to grab a section of
+       memory and point the LANCE DMA buffers to use that instead; this gets
+       slightly further but still crashes. Time-consuming investigation on various
+       hacked versions of QEMU seems to indicate that Solaris always assumes the LANCE 
+       DMA base address is fixed 0xff000000 when setting up the IOMMU for the LANCE
+       card. Hence we imitate this behaviour here. */
+    le->dmaregs[3] = 0xff000000;
+    
     push_str("/iommu/sbus/ledma");
     fword("find-device");
     PUSH(slot);
@@ -72,6 +114,13 @@ ob_le_init(unsigned int slot, unsigned long leoffset, unsigned long dmaoffset)
     push_str("reg");
     fword("property");
 
+    /* Get the IO region for Lance registers */
+    le->regs = (void *)ofmem_map_io(base + (uint64_t)leoffset, LE_REGS);
+    if (le->regs == NULL) {
+        DPRINTF("Can't map LANCE registers\n");
+        return;
+    }
+    
     push_str("/iommu/sbus/ledma/le");
     fword("find-device");
     PUSH(slot);
@@ -371,7 +420,7 @@ ob_macio_init(unsigned int slot, uint64_t base, unsigned long offset)
 #endif
 
     // NCR 92C990, Am7990, Lance. See http://www.amd.com
-    ob_le_init(slot, offset + 0x00c00000, offset + 0x00400010);
+    ob_le_init(slot, base, offset + 0x00c00000, offset + 0x00400010);
 
     // Parallel port
     //ob_bpp_init(base);
@@ -430,7 +479,7 @@ sbus_probe_slot_ss600mp(unsigned int slot, uint64_t base)
         ob_esp_init(slot, base, SS600MP_ESP, SS600MP_ESPDMA);
 #endif
         // NCR 92C990, Am7990, Lance. See http://www.amd.com
-        ob_le_init(slot, 0x00060000, SS600MP_LEBUFFER);
+        ob_le_init(slot, base, 0x00060000, SS600MP_LEBUFFER);
         // Power management (APC) XXX should not exist
         ob_apc_init(slot, APC_OFFSET);
         break;
-- 
1.7.2.5




More information about the OpenBIOS mailing list