From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1MaFj3-0005Ug-BZ for qemu-devel@nongnu.org; Sun, 09 Aug 2009 17:14:45 -0400 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1MaFix-0005S9-2U for qemu-devel@nongnu.org; Sun, 09 Aug 2009 17:14:43 -0400 Received: from [199.232.76.173] (port=36772 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1MaFiw-0005Rq-Q4 for qemu-devel@nongnu.org; Sun, 09 Aug 2009 17:14:38 -0400 Received: from mail.gmx.net ([213.165.64.20]:34321) by monty-python.gnu.org with smtp (Exim 4.60) (envelope-from ) id 1MaFiv-0001da-TP for qemu-devel@nongnu.org; Sun, 09 Aug 2009 17:14:38 -0400 Date: Sun, 9 Aug 2009 23:14:33 +0200 From: Reimar =?iso-8859-1?Q?D=F6ffinger?= Message-ID: <20090809211433.GA8892@1und1.de> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="0OAP2g/MAC+5xKAE" Content-Disposition: inline Content-Transfer-Encoding: 8bit Subject: [Qemu-devel] [PATCH] Intel 8255x/eepro100 compatibility patches List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org --0OAP2g/MAC+5xKAE Content-Type: text/plain; charset=iso-8859-1 Content-Disposition: inline Content-Transfer-Encoding: 8bit Hello everyone, I have been playing around a bit with the OS X/darwin network drivers for these cards and noticed that they seem to differ quite a bit from the Linux ones. If you're interested, the source of the core part is here: http://www.opensource.apple.com/source/AppleIntel8255x/AppleIntel8255x-19/i82557Private.cpp Attached is a series of patches that makes things work with at least some version of that (sorry, I only tried some binary I found on the net, didn't compile from source). In addition, I also used the documentation from here: http://www.intel.com/design/network/manuals/8255X_OpenSDM.htm The first patch does not set the SBAck flag for MDI interrupts when interrupts are actually disabled for MDI. I think (have not tested yet) that this is not necessary to fix anything, but according to the documentation the current code is wrong. The second patch is to ensure that a driver will not accidentally/incorrectly change the RU/CU state with a write. This is incomplete and a bit ugly, but good enough for these drivers. The third patch adds support for some kind of receive buffers "flexible mode". The Intel documentation as I read it claims that no such mode exist for receive, but the fact that those (working with real hardware I expect) drivers use it contradicts that... This _definitely_ is necessary to support these drivers. And the last patch expands received data shorter than 60 bytes so no short-frame detection is incorrectly triggered, and of course also throws away all short-frame detection code since it makes no sense. It was also wrong since size is without CRC and thus the short frame limit is 60, not 64. And related to that (but without a patch), I think that the > } else if ((size > MAX_ETH_FRAME_SIZE + 4) && !(s->configuration[18] & 8)) { check is wrong, too, and the + 4 should not be there... Back to the patch, e.g. the rtl8139 driver also expands those frames (and I just copied the code for that). This too _definitely_ is necessary to support these drivers. Hope this is interesting to someone and maybe we can even get these merged... Thanks, Reimar Döffinger --0OAP2g/MAC+5xKAE Content-Type: text/plain; charset=iso-8859-1 Content-Disposition: attachment; filename="0001-Setting-the-MDI-SCBAck-flag-when-interrupts-for-MDI-.patch" >>From cdd96658f21e571c077fee08a4ba64e79d49c0b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Reimar=20D=C3=B6ffinger?= Date: Sun, 9 Aug 2009 21:36:45 +0200 Subject: [PATCH 1/4] Setting the MDI SCBAck flag when interrupts for MDI are disabled is wrong, even if it does not seem to cause any real issue with known drivers. --- hw/eepro100.c | 4 +--- 1 files changed, 1 insertions(+), 3 deletions(-) diff --git a/hw/eepro100.c b/hw/eepro100.c index ec31a6a..bf5d920 100644 --- a/hw/eepro100.c +++ b/hw/eepro100.c @@ -1043,9 +1043,7 @@ static void eepro100_write_mdi(EEPRO100State * s, uint32_t val) } data = s->mdimem[reg]; } - /* Emulation takes no time to finish MDI transaction. - * Set MDI bit in SCB status register. */ - s->mem[SCBAck] |= 0x08; + /* Emulation takes no time to finish MDI transaction. */ val |= BIT(28); if (raiseint) { eepro100_mdi_interrupt(s); -- 1.6.4 --0OAP2g/MAC+5xKAE Content-Type: text/plain; charset=iso-8859-1 Content-Disposition: attachment; filename="0002-Hack-to-make-sure-that-drivers-like-AppleIntel8255x-.patch" >>From 84f2d6ecf89c1dbd5f83676251aa2f646e2270b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Reimar=20D=C3=B6ffinger?= Date: Sun, 9 Aug 2009 21:39:36 +0200 Subject: [PATCH 2/4] Hack to make sure that drivers like AppleIntel8255x will not meddle with the RU/CU state when the ACK the interrupt with a 16 bit write. --- hw/eepro100.c | 4 ++++ 1 files changed, 4 insertions(+), 0 deletions(-) diff --git a/hw/eepro100.c b/hw/eepro100.c index bf5d920..f619d36 100644 --- a/hw/eepro100.c +++ b/hw/eepro100.c @@ -1249,7 +1249,11 @@ static void eepro100_write1(EEPRO100State * s, uint32_t addr, uint8_t val) static void eepro100_write2(EEPRO100State * s, uint32_t addr, uint16_t val) { if (addr <= sizeof(s->mem) - sizeof(val)) { + ru_state_t rtmp = get_ru_state(s); + cu_state_t ctmp = get_cu_state(s); memcpy(&s->mem[addr], &val, sizeof(val)); + set_cu_state(s, ctmp); + set_ru_state(s, rtmp); } logout("addr=%s val=0x%04x\n", regname(addr), val); -- 1.6.4 --0OAP2g/MAC+5xKAE Content-Type: text/plain; charset=iso-8859-1 Content-Disposition: attachment; filename="0003-Add-support-for-receiving-via-receive-buffers.patch" Content-Transfer-Encoding: 8bit >>From 670b2dcb0a0914415f58eabf56c304f72c9c23b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Reimar=20D=C3=B6ffinger?= Date: Sun, 9 Aug 2009 20:06:46 +0200 Subject: [PATCH 3/4] Add support for receiving via receive buffers. While the Intel documentation claims this is unsupported, the OS X drivers use it, causing an assertion failure since rx buffer size is 0. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Reimar Döffinger --- hw/eepro100.c | 27 ++++++++++++++++++++++++--- 1 files changed, 24 insertions(+), 3 deletions(-) diff --git a/hw/eepro100.c b/hw/eepro100.c index f619d36..5620bc7 100644 --- a/hw/eepro100.c +++ b/hw/eepro100.c @@ -153,6 +153,14 @@ typedef struct { char packet[MAX_ETH_FRAME_SIZE + 4]; } eepro100_rx_t; +/* Receive buffer descriptor. */ +typedef struct { + uint32_t count; + uint32_t link; + uint32_t buffer; + uint32_t size; +} eepro100_rbd_t; + typedef struct { uint32_t tx_good_frames, tx_max_collisions, tx_late_collisions, tx_underruns, tx_lost_crs, tx_deferred, tx_single_collisions, @@ -218,6 +226,7 @@ typedef struct { /* (ru_base + ru_offset) address the RFD in the Receive Frame Area. */ uint32_t ru_base; /* RU base address */ uint32_t ru_offset; /* RU address offset */ + uint32_t rbd_addr; uint32_t statsaddr; /* pointer to eepro100_stats_t */ eepro100_stats_t statistics; /* statistical counters */ #if 0 @@ -843,6 +852,7 @@ static void eepro100_ru_command(EEPRO100State * s, uint8_t val) } set_ru_state(s, ru_ready); s->ru_offset = s->pointer; + s->rbd_addr = 0; logout("val=0x%02x (rx start)\n", val); break; case RX_RESUME: @@ -1512,7 +1522,19 @@ static ssize_t nic_receive(VLANClientState *vc, const uint8_t * buf, size_t size cpu_physical_memory_read(s->ru_base + s->ru_offset, (uint8_t *) & rx, offsetof(eepro100_rx_t, packet)); uint16_t rfd_command = le16_to_cpu(rx.command); - uint16_t rfd_size = le16_to_cpu(rx.size); + uint32_t rfd_size = le16_to_cpu(rx.size); + uint32_t dst_addr = s->ru_base + s->ru_offset + offsetof(eepro100_rx_t, packet); + if (rfd_command & 8) { + // argh! Flexible mode. Intel docs say it is not support but the Mac OS driver uses it anyway. + eepro100_rbd_t rbd; + if (!s->rbd_addr) + s->rbd_addr = le32_to_cpu(rx.rx_buf_addr); + cpu_physical_memory_read(s->rbd_addr, (uint8_t *) & rbd, sizeof(rbd)); + rfd_size = le32_to_cpu(rbd.size); + dst_addr = le32_to_cpu(rbd.buffer); + stl_phys(s->rbd_addr + offsetof(eepro100_rbd_t, count), size | 0x8000); + s->rbd_addr = le32_to_cpu(rbd.link); + } assert(size <= rfd_size); if (size < 64) { rfd_status |= 0x0080; @@ -1528,8 +1550,7 @@ static ssize_t nic_receive(VLANClientState *vc, const uint8_t * buf, size_t size assert(!(s->configuration[18] & 4)); /* TODO: check stripping enable bit. */ //~ assert(!(s->configuration[17] & 1)); - cpu_physical_memory_write(s->ru_base + s->ru_offset + - offsetof(eepro100_rx_t, packet), buf, size); + cpu_physical_memory_write(dst_addr, buf, size); s->statistics.rx_good_frames++; eepro100_fr_interrupt(s); s->ru_offset = le32_to_cpu(rx.link); -- 1.6.4 --0OAP2g/MAC+5xKAE Content-Type: text/plain; charset=iso-8859-1 Content-Disposition: attachment; filename="0004-Short-frames-do-not-exist-so-remove-code-to-handle-t.patch" Content-Transfer-Encoding: 8bit >>From da19bed5b3ac1b409f0db91c881983360fbde946 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Reimar=20D=C3=B6ffinger?= Date: Sun, 9 Aug 2009 22:57:06 +0200 Subject: [PATCH 4/4] Short frames do not exist, so remove code to handle them. Also expand packets that are smaller than the shor frame limit, otherwise the OS X network stack seems to discard them. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Reimar Döffinger --- hw/eepro100.c | 20 +++++++++++--------- 1 files changed, 11 insertions(+), 9 deletions(-) diff --git a/hw/eepro100.c b/hw/eepro100.c index 5620bc7..d2c18cc 100644 --- a/hw/eepro100.c +++ b/hw/eepro100.c @@ -1452,6 +1452,8 @@ static int nic_can_receive(VLANClientState *vc) //~ return !eepro100_buffer_full(s); } +#define MIN_BUF_SIZE 60 + static ssize_t nic_receive(VLANClientState *vc, const uint8_t * buf, size_t size) { /* TODO: @@ -1459,6 +1461,7 @@ static ssize_t nic_receive(VLANClientState *vc, const uint8_t * buf, size_t size * - Interesting packets should set bit 29 in power management driver register. */ EEPRO100State *s = vc->opaque; + uint8_t buf1[MIN_BUF_SIZE]; uint16_t rfd_status = 0xa000; static const uint8_t broadcast_macaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; @@ -1466,16 +1469,18 @@ static ssize_t nic_receive(VLANClientState *vc, const uint8_t * buf, size_t size /* TODO: check multiple IA bit. */ assert(!(s->configuration[20] & BIT(6))); + /* Short frames can not happen on virtual hardware, so expand them. */ + if (size < MIN_BUF_SIZE) { + memcpy(buf1, buf, size); + memset(buf1 + size, 0, MIN_BUF_SIZE - size); + buf = buf1; + size = MIN_BUF_SIZE; + } + if (s->configuration[8] & 0x80) { /* CSMA is disabled. */ logout("%p received while CSMA is disabled\n", s); return -1; - } else if (size < 64 && (s->configuration[7] & 1)) { - /* Short frame and configuration byte 7/0 (discard short receive) set: - * Short frame is discarded */ - logout("%p received short frame (%d byte)\n", s, size); - s->statistics.rx_short_frame_errors++; - //~ return -1; } else if ((size > MAX_ETH_FRAME_SIZE + 4) && !(s->configuration[18] & 8)) { /* Long frame and configuration byte 18/3 (long receive ok) not set: * Long frames are discarded. */ @@ -1536,9 +1541,6 @@ static ssize_t nic_receive(VLANClientState *vc, const uint8_t * buf, size_t size s->rbd_addr = le32_to_cpu(rbd.link); } assert(size <= rfd_size); - if (size < 64) { - rfd_status |= 0x0080; - } logout("command 0x%04x, link 0x%08x, addr 0x%08x, size %u\n", rfd_command, rx.link, rx.rx_buf_addr, rfd_size); stw_phys(s->ru_base + s->ru_offset + offsetof(eepro100_rx_t, status), -- 1.6.4 --0OAP2g/MAC+5xKAE--