Module Name: src
Committed By: tsutsui
Date: Tue May 5 15:47:35 UTC 2009
Modified Files:
src/sys/dev/ic: i82596.c i82596var.h
Log Message:
Add support for i82596 Rev A chip which doesn't have the enhanced 32 bit
big endian mode:
- add IEE_REV_A flag to indicate if chip support the 32 bit BE mode or not
- add IEE_SWAPA32() macro and use it on necessary 32 bit DMA pointers
- rename IEE_SWAP() macro for the SCP address pointer and statistics
counters which require word swap even on Rev B/C chips to IEE_SWAP32()
for clarification
- add comments about these BE mode quirks
Tested on HP9000 735/125 by me and also tested on 715/50 by skrll@
with netbsd-5 branch, and fixes MI part of PR port-hp700/35531.
To generate a diff of this commit:
cvs rdiff -u -r1.19 -r1.20 src/sys/dev/ic/i82596.c
cvs rdiff -u -r1.10 -r1.11 src/sys/dev/ic/i82596var.h
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/dev/ic/i82596.c
diff -u src/sys/dev/ic/i82596.c:1.19 src/sys/dev/ic/i82596.c:1.20
--- src/sys/dev/ic/i82596.c:1.19 Fri Apr 4 17:03:42 2008
+++ src/sys/dev/ic/i82596.c Tue May 5 15:47:35 2009
@@ -1,4 +1,4 @@
-/* $NetBSD: i82596.c,v 1.19 2008/04/04 17:03:42 tsutsui Exp $ */
+/* $NetBSD: i82596.c,v 1.20 2009/05/05 15:47:35 tsutsui Exp $ */
/*
* Copyright (c) 2003 Jochen Kunz.
@@ -43,7 +43,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: i82596.c,v 1.19 2008/04/04 17:03:42 tsutsui Exp $");
+__KERNEL_RCSID(0, "$NetBSD: i82596.c,v 1.20 2009/05/05 15:47:35 tsutsui Exp $");
/* autoconfig and device stuff */
#include <sys/param.h>
@@ -123,10 +123,28 @@
* MI backend doesn't distinguish different chip types when programming
* the chip.
*
- * sc->sc_flags has to be set to 0 on little endian hardware and to
- * IEE_NEED_SWAP on big endian hardware, when endianess conversion is not
- * done by the bus attachment. Usually you need to set IEE_NEED_SWAP
- * when IEE_SYSBUS_BE is set in the sysbus byte.
+ * IEE_NEED_SWAP in sc->sc_flags has to be cleared on little endian hardware
+ * and set on big endian hardware, when endianess conversion is not done
+ * by the bus attachment but done by i82596 chip itself.
+ * Usually you need to set IEE_NEED_SWAP on big endian machines
+ * where the hardware (the LE/~BE pin) is configured as BE mode.
+ *
+ * If the chip is configured as BE mode, all 8 bit (byte) and 16 bit (word)
+ * entities can be written in big endian. But Rev A chip doesn't support
+ * 32 bit (dword) entities with big endian byte ordering, so we have to
+ * treat all 32 bit (dword) entities as two 16 bit big endian entities.
+ * Rev B and C chips support big endian byte ordering for 32 bit entities,
+ * and this new feature is enabled by IEE_SYSBUS_BE in the sysbus byte.
+ *
+ * With the IEE_SYSBUS_BE feature, all 32 bit address ponters are
+ * treated as true 32 bit entities but the SCB absolute address and
+ * statistical counters are still treated as two 16 bit big endian entities,
+ * so we have to always swap high and low words for these entities.
+ * IEE_SWAP32() should be used for the SCB address and statistical counters,
+ * and IEE_SWAPA32() should be used for other 32 bit pointers in the shmem.
+ *
+ * IEE_REV_A flag must be set in sc->sc_flags if the IEE_SYSBUS_BE feature
+ * is disabled even on big endian machines for the old Rev A chip in backend.
*
* sc->sc_cl_align must be set to 1 or to the cache line size. When set to
* 1 no special alignment of DMA descriptors is done. If sc->sc_cl_align != 1
@@ -256,7 +274,7 @@
sc->sc_rx_mbuf[sc->sc_rx_done] = new_mbuf;
rbd->rbd_count = 0;
rbd->rbd_size = IEE_RBD_EL | rx_map->dm_segs[0].ds_len;
- rbd->rbd_rb_addr = rx_map->dm_segs[0].ds_addr;
+ rbd->rbd_rb_addr = IEE_SWAPA32(rx_map->dm_segs[0].ds_addr);
sc->sc_rx_done = (sc->sc_rx_done + 1) % IEE_NRFD;
rfd = SC_RFD(sc->sc_rx_done);
}
@@ -266,16 +284,19 @@
/* Receive Overrun, reinit receive ring buffer. */
for (n = 0 ; n < IEE_NRFD ; n++) {
SC_RFD(n)->rfd_cmd = IEE_RFD_SF;
- SC_RFD(n)->rfd_link_addr = IEE_PHYS_SHMEM(IEE_RFD_OFF
- + IEE_RFD_SZ * ((n + 1) % IEE_NRFD));
- SC_RBD(n)->rbd_next_rbd = IEE_PHYS_SHMEM(IEE_RBD_OFF
- + IEE_RBD_SZ * ((n + 1) % IEE_NRFD));
+ SC_RFD(n)->rfd_link_addr =
+ IEE_SWAPA32(IEE_PHYS_SHMEM(IEE_RFD_OFF
+ + IEE_RFD_SZ * ((n + 1) % IEE_NRFD)));
+ SC_RBD(n)->rbd_next_rbd =
+ IEE_SWAPA32(IEE_PHYS_SHMEM(IEE_RBD_OFF
+ + IEE_RBD_SZ * ((n + 1) % IEE_NRFD)));
SC_RBD(n)->rbd_size = IEE_RBD_EL |
sc->sc_rx_map[n]->dm_segs[0].ds_len;
SC_RBD(n)->rbd_rb_addr =
- sc->sc_rx_map[n]->dm_segs[0].ds_addr;
+ IEE_SWAPA32(sc->sc_rx_map[n]->dm_segs[0].ds_addr);
}
- SC_RFD(0)->rfd_rbd_addr = IEE_PHYS_SHMEM(IEE_RBD_OFF);
+ SC_RFD(0)->rfd_rbd_addr =
+ IEE_SWAPA32(IEE_PHYS_SHMEM(IEE_RBD_OFF));
sc->sc_rx_done = 0;
bus_dmamap_sync(sc->sc_dmat, sc->sc_shmem_map, IEE_RFD_OFF,
IEE_RFD_LIST_SZ + IEE_RBD_LIST_SZ, BUS_DMASYNC_PREWRITE);
@@ -330,33 +351,33 @@
/* Try to get deferred packets going. */
iee_start(ifp);
}
- if (IEE_SWAP(SC_SCB->scb_crc_err) != sc->sc_crc_err) {
- sc->sc_crc_err = IEE_SWAP(SC_SCB->scb_crc_err);
+ if (IEE_SWAP32(SC_SCB->scb_crc_err) != sc->sc_crc_err) {
+ sc->sc_crc_err = IEE_SWAP32(SC_SCB->scb_crc_err);
printf("%s: iee_intr: crc_err=%d\n", device_xname(sc->sc_dev),
sc->sc_crc_err);
}
- if (IEE_SWAP(SC_SCB->scb_align_err) != sc->sc_align_err) {
- sc->sc_align_err = IEE_SWAP(SC_SCB->scb_align_err);
+ if (IEE_SWAP32(SC_SCB->scb_align_err) != sc->sc_align_err) {
+ sc->sc_align_err = IEE_SWAP32(SC_SCB->scb_align_err);
printf("%s: iee_intr: align_err=%d\n", device_xname(sc->sc_dev),
sc->sc_align_err);
}
- if (IEE_SWAP(SC_SCB->scb_resource_err) != sc->sc_resource_err) {
- sc->sc_resource_err = IEE_SWAP(SC_SCB->scb_resource_err);
+ if (IEE_SWAP32(SC_SCB->scb_resource_err) != sc->sc_resource_err) {
+ sc->sc_resource_err = IEE_SWAP32(SC_SCB->scb_resource_err);
printf("%s: iee_intr: resource_err=%d\n",
device_xname(sc->sc_dev), sc->sc_resource_err);
}
- if (IEE_SWAP(SC_SCB->scb_overrun_err) != sc->sc_overrun_err) {
- sc->sc_overrun_err = IEE_SWAP(SC_SCB->scb_overrun_err);
+ if (IEE_SWAP32(SC_SCB->scb_overrun_err) != sc->sc_overrun_err) {
+ sc->sc_overrun_err = IEE_SWAP32(SC_SCB->scb_overrun_err);
printf("%s: iee_intr: overrun_err=%d\n",
device_xname(sc->sc_dev), sc->sc_overrun_err);
}
- if (IEE_SWAP(SC_SCB->scb_rcvcdt_err) != sc->sc_rcvcdt_err) {
- sc->sc_rcvcdt_err = IEE_SWAP(SC_SCB->scb_rcvcdt_err);
+ if (IEE_SWAP32(SC_SCB->scb_rcvcdt_err) != sc->sc_rcvcdt_err) {
+ sc->sc_rcvcdt_err = IEE_SWAP32(SC_SCB->scb_rcvcdt_err);
printf("%s: iee_intr: rcvcdt_err=%d\n",
device_xname(sc->sc_dev), sc->sc_rcvcdt_err);
}
- if (IEE_SWAP(SC_SCB->scb_short_fr_err) != sc->sc_short_fr_err) {
- sc->sc_short_fr_err = IEE_SWAP(SC_SCB->scb_short_fr_err);
+ if (IEE_SWAP32(SC_SCB->scb_short_fr_err) != sc->sc_short_fr_err) {
+ sc->sc_short_fr_err = IEE_SWAP32(SC_SCB->scb_short_fr_err);
printf("%s: iee_intr: short_fr_err=%d\n",
device_xname(sc->sc_dev), sc->sc_short_fr_err);
}
@@ -476,8 +497,9 @@
iee_cb_setup(sc, IEE_CB_CMD_CONF);
break;
case IEE_CB_CMD_TR: /* Transmit */
- cb->cb_transmit.tx_tbd_addr = IEE_PHYS_SHMEM(IEE_TBD_OFF
- + IEE_TBD_SZ * sc->sc_next_tbd);
+ cb->cb_transmit.tx_tbd_addr =
+ IEE_SWAPA32(IEE_PHYS_SHMEM(IEE_TBD_OFF
+ + IEE_TBD_SZ * sc->sc_next_tbd));
cb->cb_cmd |= IEE_CB_SF; /* Always use Flexible Mode. */
break;
case IEE_CB_CMD_TDR: /* Time Domain Reflectometry */
@@ -490,8 +512,8 @@
/* can't happen */
break;
}
- cb->cb_link_addr = IEE_PHYS_SHMEM(IEE_CB_OFF + IEE_CB_SZ *
- (sc->sc_next_cb + 1));
+ cb->cb_link_addr = IEE_SWAPA32(IEE_PHYS_SHMEM(IEE_CB_OFF + IEE_CB_SZ *
+ (sc->sc_next_cb + 1)));
bus_dmamap_sync(sc->sc_dmat, sc->sc_shmem_map, IEE_CB_OFF
+ IEE_CB_SZ * sc->sc_next_cb, IEE_CB_SZ, BUS_DMASYNC_PREWRITE);
sc->sc_next_cb++;
@@ -510,14 +532,14 @@
/* Set pointer to Intermediate System Configuration Pointer. */
/* Phys. addr. in big endian order. (Big endian as defined by Intel.) */
- SC_SCP->scp_iscp_addr = IEE_SWAP(IEE_PHYS_SHMEM(IEE_ISCP_OFF));
+ SC_SCP->scp_iscp_addr = IEE_SWAP32(IEE_PHYS_SHMEM(IEE_ISCP_OFF));
/* Set pointer to System Control Block. */
/* Phys. addr. in big endian order. (Big endian as defined by Intel.) */
- SC_ISCP->iscp_scb_addr = IEE_SWAP(IEE_PHYS_SHMEM(IEE_SCB_OFF));
+ SC_ISCP->iscp_scb_addr = IEE_SWAP32(IEE_PHYS_SHMEM(IEE_SCB_OFF));
/* Set pointer to Receive Frame Area. (physical address) */
- SC_SCB->scb_rfa_addr = IEE_PHYS_SHMEM(IEE_RFD_OFF);
+ SC_SCB->scb_rfa_addr = IEE_SWAPA32(IEE_PHYS_SHMEM(IEE_RFD_OFF));
/* Set pointer to Command Block. (physical address) */
- SC_SCB->scb_cmd_blk_addr = IEE_PHYS_SHMEM(IEE_CB_OFF);
+ SC_SCB->scb_cmd_blk_addr = IEE_SWAPA32(IEE_PHYS_SHMEM(IEE_CB_OFF));
ifmedia_init(&sc->sc_ifmedia, 0, iee_mediachange, iee_mediastatus);
if (media != NULL) {
@@ -656,12 +678,12 @@
}
for (n = 0 ; n < sc->sc_tx_map[t]->dm_nsegs ; n++) {
SC_TBD(sc->sc_next_tbd + n)->tbd_tb_addr =
- sc->sc_tx_map[t]->dm_segs[n].ds_addr;
+ IEE_SWAPA32(sc->sc_tx_map[t]->dm_segs[n].ds_addr);
SC_TBD(sc->sc_next_tbd + n)->tbd_size =
sc->sc_tx_map[t]->dm_segs[n].ds_len;
SC_TBD(sc->sc_next_tbd + n)->tbd_link_addr =
- IEE_PHYS_SHMEM(IEE_TBD_OFF + IEE_TBD_SZ
- * (sc->sc_next_tbd + n + 1));
+ IEE_SWAPA32(IEE_PHYS_SHMEM(IEE_TBD_OFF + IEE_TBD_SZ
+ * (sc->sc_next_tbd + n + 1)));
}
SC_TBD(sc->sc_next_tbd + n - 1)->tbd_size |= IEE_CB_EL;
bus_dmamap_sync(sc->sc_dmat, sc->sc_tx_map[t], 0,
@@ -778,11 +800,13 @@
memset(SC_RBD(0), 0, IEE_RBD_LIST_SZ);
for (r = 0 ; r < IEE_NRFD ; r++) {
SC_RFD(r)->rfd_cmd = IEE_RFD_SF;
- SC_RFD(r)->rfd_link_addr = IEE_PHYS_SHMEM(IEE_RFD_OFF
- + IEE_RFD_SZ * ((r + 1) % IEE_NRFD));
-
- SC_RBD(r)->rbd_next_rbd = IEE_PHYS_SHMEM(IEE_RBD_OFF
- + IEE_RBD_SZ * ((r + 1) % IEE_NRFD));
+ SC_RFD(r)->rfd_link_addr =
+ IEE_SWAPA32(IEE_PHYS_SHMEM(IEE_RFD_OFF
+ + IEE_RFD_SZ * ((r + 1) % IEE_NRFD)));
+
+ SC_RBD(r)->rbd_next_rbd =
+ IEE_SWAPA32(IEE_PHYS_SHMEM(IEE_RBD_OFF
+ + IEE_RBD_SZ * ((r + 1) % IEE_NRFD)));
if (sc->sc_rx_mbuf[r] == NULL) {
MGETHDR(sc->sc_rx_mbuf[r], M_DONTWAIT, MT_DATA);
if (sc->sc_rx_mbuf[r] == NULL) {
@@ -824,9 +848,10 @@
bus_dmamap_sync(sc->sc_dmat, sc->sc_rx_map[r], 0,
sc->sc_rx_mbuf[r]->m_ext.ext_size, BUS_DMASYNC_PREREAD);
SC_RBD(r)->rbd_size = sc->sc_rx_map[r]->dm_segs[0].ds_len;
- SC_RBD(r)->rbd_rb_addr= sc->sc_rx_map[r]->dm_segs[0].ds_addr;
+ SC_RBD(r)->rbd_rb_addr =
+ IEE_SWAPA32(sc->sc_rx_map[r]->dm_segs[0].ds_addr);
}
- SC_RFD(0)->rfd_rbd_addr = IEE_PHYS_SHMEM(IEE_RBD_OFF);
+ SC_RFD(0)->rfd_rbd_addr = IEE_SWAPA32(IEE_PHYS_SHMEM(IEE_RBD_OFF));
if (err != 0) {
for (n = 0 ; n < r; n++) {
m_freem(sc->sc_rx_mbuf[n]);
@@ -860,7 +885,7 @@
sc->sc_cf[12] = IEE_CF_12_DEF;
sc->sc_cf[13] = IEE_CF_13_DEF;
iee_cb_setup(sc, IEE_CB_CMD_CONF | IEE_CB_S | IEE_CB_EL);
- SC_SCB->scb_rfa_addr = IEE_PHYS_SHMEM(IEE_RFD_OFF);
+ SC_SCB->scb_rfa_addr = IEE_SWAPA32(IEE_PHYS_SHMEM(IEE_RFD_OFF));
bus_dmamap_sync(sc->sc_dmat, sc->sc_shmem_map, 0, IEE_SHMEM_MAX,
BUS_DMASYNC_PREWRITE);
(sc->sc_iee_cmd)(sc, IEE_SCB_CUC_EXE | IEE_SCB_RUC_ST);
Index: src/sys/dev/ic/i82596var.h
diff -u src/sys/dev/ic/i82596var.h:1.10 src/sys/dev/ic/i82596var.h:1.11
--- src/sys/dev/ic/i82596var.h:1.10 Fri Apr 4 17:03:42 2008
+++ src/sys/dev/ic/i82596var.h Tue May 5 15:47:35 2009
@@ -1,4 +1,4 @@
-/* $NetBSD: i82596var.h,v 1.10 2008/04/04 17:03:42 tsutsui Exp $ */
+/* $NetBSD: i82596var.h,v 1.11 2009/05/05 15:47:35 tsutsui Exp $ */
/*
* Copyright (c) 2003 Jochen Kunz.
@@ -189,10 +189,23 @@
/* Flags */
#define IEE_NEED_SWAP 0x01
-#define IEE_WANT_MCAST 0x02
+#define IEE_WANT_MCAST 0x02
+#define IEE_REV_A 0x04
-#define IEE_SWAP(x) ((sc->sc_flags & IEE_NEED_SWAP) == 0 ? x : \
- (((x) << 16) | ((x) >> 16)))
+/*
+ * Rev A1 chip doesn't have 32-bit BE mode and all 32 bit pointers are
+ * treated as two 16-bit big endian entities.
+ */
+#define IEE_SWAPA32(x) ((sc->sc_flags & (IEE_NEED_SWAP|IEE_REV_A)) == \
+ (IEE_NEED_SWAP|IEE_REV_A) ? \
+ (((x) << 16) | ((x) >> 16)) : (x))
+/*
+ * The SCB absolute address and statistical counters are
+ * always treated as two 16-bit big endian entities
+ * even in 32-bit BE mode supported by Rev B and C chips.
+ */
+#define IEE_SWAP32(x) ((sc->sc_flags & IEE_NEED_SWAP) != 0 ? \
+ (((x) << 16) | ((x) >> 16)) : (x))
#define IEE_PHYS_SHMEM(x) ((uint32_t) (sc->sc_shmem_map->dm_segs[0].ds_addr \
+ (x)))