Author: mcayland Date: Wed Apr 27 21:20:10 2011 New Revision: 1037 URL: http://tracker.coreboot.org/trac/openbios/changeset/1037
Log: Fix up LANCE ethernet DMA mapping under Solaris 8 on SPARC32.
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@siriusit.co.uk
Modified: trunk/openbios-devel/config/examples/sparc32_config.xml trunk/openbios-devel/drivers/sbus.c
Modified: trunk/openbios-devel/config/examples/sparc32_config.xml ============================================================================== --- trunk/openbios-devel/config/examples/sparc32_config.xml Wed Apr 27 21:20:06 2011 (r1036) +++ trunk/openbios-devel/config/examples/sparc32_config.xml Wed Apr 27 21:20:10 2011 (r1037) @@ -63,6 +63,7 @@
<!-- Drivers --> <option name="CONFIG_DRIVER_SBUS" type="boolean" value="true"/> + <option name="CONFIG_DEBUG_SBUS" type="boolean" value="false"/> <option name="CONFIG_DRIVER_OBIO" type="boolean" value="true"/> <option name="CONFIG_DRIVER_ESP" type="boolean" value="true"/> <option name="CONFIG_DRIVER_FLOPPY" type="boolean" value="true"/>
Modified: trunk/openbios-devel/drivers/sbus.c ============================================================================== --- trunk/openbios-devel/drivers/sbus.c Wed Apr 27 21:20:06 2011 (r1036) +++ trunk/openbios-devel/drivers/sbus.c Wed Apr 27 21:20:10 2011 (r1037) @@ -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 @@ }
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 @@ 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 @@ #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 @@ 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;