Running FreeBSD 10 on HP Integrity rx2800-i4

Meyer, Wolfgang wolfgang.meyer at hob.de
Fri Feb 26 16:27:06 UTC 2016


Hello,

as the release of FreeBSD 10.3 is prepared, I thought I could share some patches that are necessary for running FreeBSD 10 on HP Integrity rx2800-i4 servers. I'll also try to explain what the patches are trying to fix (from the top of my head as it has been some time since the creation of the patches).

The original efi_md_find function assumes that the efi memory descriptors are sorted by physical addresses. This is not the case for the EFI of the HP Integrity rx2800-i4 servers and hence some memory regions occupied by efi memory descriptors are not found which leads to a boot failure (not sure if machine check or hang). The following patch fixes this behaviour.

efi.patch:
--- sys/ia64/ia64/efi.c.orig    2015-07-31 14:18:37.000000000 +0200
+++ sys/ia64/ia64/efi.c 2015-08-13 16:15:53.631602000 +0200
@@ -205,21 +205,28 @@
 efi_md_find(vm_paddr_t pa)
 {
        static struct efi_md *last = NULL;
-       struct efi_md *md, *p0, *p1;
+       struct efi_md *md, *md0;
+       int up = 0;

        md = (last != NULL) ? last : efi_md_first();
-       p1 = p0 = NULL;
-       while (md != NULL && md != p1) {
+       if (md == NULL) {
+               return (NULL);
+       }
+       md0 = md;
+       up = (pa > md->md_phys) ? 1 : 0;
+
+       do {
                if (pa >= md->md_phys &&
-                   pa < md->md_phys + md->md_pages * EFI_PAGE_SIZE) {
+                       pa < md->md_phys + md->md_pages * EFI_PAGE_SIZE) {
                        last = md;
                        return (md);
                }

-               p1 = p0;
-               p0 = md;
-               md = (pa < md->md_phys) ? efi_md_prev(md) : efi_md_next(md);
-       }
+               md = up ? efi_md_next(md) : efi_md_prev(md);
+               if (md == NULL) {
+                       md = up ? efi_md_first() : efi_md_last();
+               }
+       } while (md != md0);

        return (NULL);
 }

The firmware of the HP Integrity rx2800-i4 contains a myriad of small memory descriptors of the type EFI_MD_TYPE_BS_CODE and EFI_MD_TYPE_BS_DATA. Trying to use them für the physmem map overburdens the structures holding the descriptors. Increasing the size of the structures doesn't help. The solution is not to use them for the physmem map. Furthermore the mapping pagesize shift should not be odd (as is the case for the rx2800 firmware).

machdep.patch:
--- sys/ia64/ia64/machdep.c.orig        2015-07-31 14:18:23.000000000 +0200
+++ sys/ia64/ia64/machdep.c     2015-08-13 15:59:29.624985000 +0200
@@ -622,6 +622,9 @@
                shft++;
                sz >>= 1;
        }
+       if (shft & 1) {
+               shft++;
+       }

        pte = PTE_PRESENT | PTE_MA_WB | PTE_ACCESSED | PTE_DIRTY |
            PTE_PL_KERN | PTE_AR_RWX;
@@ -761,11 +764,11 @@
                case EFI_MD_TYPE_RECLAIM:
                case EFI_MD_TYPE_RT_CODE:
                case EFI_MD_TYPE_RT_DATA:
+               case EFI_MD_TYPE_BS_CODE:
+               case EFI_MD_TYPE_BS_DATA:
                        /* Don't use these memory regions. */
                        ia64_physmem_track(md->md_phys, mdlen);
                        break;
-               case EFI_MD_TYPE_BS_CODE:
-               case EFI_MD_TYPE_BS_DATA:
                case EFI_MD_TYPE_CODE:
                case EFI_MD_TYPE_DATA:
                case EFI_MD_TYPE_FREE:
--- sys/ia64/ia64/dump_machdep.c.orig   2015-08-13 07:59:43.000000000 +0200
+++ sys/ia64/ia64/dump_machdep.c        2015-08-13 15:59:04.582524000 +0200
@@ -203,9 +203,7 @@
        while (mdp != NULL) {
                if (mdp->md_type == EFI_MD_TYPE_FREE ||
                    mdp->md_type == EFI_MD_TYPE_DATA ||
-                   mdp->md_type == EFI_MD_TYPE_CODE ||
-                   mdp->md_type == EFI_MD_TYPE_BS_DATA ||
-                   mdp->md_type == EFI_MD_TYPE_BS_CODE) {
+                   mdp->md_type == EFI_MD_TYPE_CODE) {
                        error = (*cb)(mdp, seqnr++, arg);
                        if (error)
                                return (-error);

The igb driver has alignment issues that lead to kernel panics. Furthermore watchdog timeouts drag the network interface down regularily and are also causing kernel panics. The following patch fixes this. Alas the network driver still has some severe issues that hampers the usage (for example remote access via ssh). Ping rtts on the local network are on average in the order of hundreds of milliseconds. On FreeBSD 9 the igb driver also needs fixing due to alignment issues and watchdog timeouts but there the network performance in the end is satisfying with ping rtts in the sub-millisecond regime.

if_igb.patch:
--- sys/dev/e1000/if_igb.h.orig 2016-02-26 13:10:58.344796000 +0100
+++ sys/dev/e1000/if_igb.h      2016-02-26 13:55:00.420598000 +0100
@@ -599,6 +599,8 @@
 #define        IGB_RX_UNLOCK(_sc)              mtx_unlock(&(_sc)->rx_mtx)
 #define        IGB_RX_LOCK_ASSERT(_sc)         mtx_assert(&(_sc)->rx_mtx, MA_OWNED)

+#define        IGB_RXBUF_ALIGN         (sizeof(uint32_t))
+
 #define UPDATE_VF_REG(reg, last, cur)          \
 {                                              \
        u32 new = E1000_READ_REG(hw, reg);      \
--- sys/dev/e1000/if_igb.c.orig 2016-02-26 13:11:36.634944000 +0100
+++ sys/dev/e1000/if_igb.c      2016-02-26 14:19:43.271194000 +0100
@@ -171,6 +171,9 @@
 static __inline        void igb_rx_discard(struct rx_ring *, int);
 static __inline void igb_rx_input(struct rx_ring *,
                    struct ifnet *, struct mbuf *, u32);
+#ifndef __NO_STRICT_ALIGNMENT
+static __inline void igb_fixup_rx(struct mbuf *);
+#endif

 static bool    igb_rxeof(struct igb_queue *, int, int *);
 static void    igb_rx_checksum(u32, struct mbuf *, u32);
@@ -3993,7 +3996,8 @@
        ** would have been taken, so none processed
        ** for too long indicates a hang.
        */
-       if ((!processed) && ((ticks - txr->watchdog_time) > IGB_WATCHDOG))
+       if ((!processed) && ((ticks - txr->watchdog_time) > IGB_WATCHDOG) &&
+               txr->queue_status == IGB_QUEUE_WORKING)
                txr->queue_status |= IGB_QUEUE_HUNG;

        if (txr->tx_avail >= IGB_QUEUE_THRESHOLD)
@@ -4051,6 +4055,9 @@
                mh->m_pkthdr.len = mh->m_len = MHLEN;
                mh->m_len = MHLEN;
                mh->m_flags |= M_PKTHDR;
+#ifndef __NO_STRICT_ALIGNMENT
+               m_adj(mh, IGB_RXBUF_ALIGN);
+#endif
                /* Get the memory mapping */
                error = bus_dmamap_load_mbuf_sg(rxr->htag,
                    rxbuf->hmap, mh, hseg, &nsegs, BUS_DMA_NOWAIT);
@@ -4076,6 +4083,9 @@
                        mp = rxbuf->m_pack;

                mp->m_pkthdr.len = mp->m_len = adapter->rx_mbuf_sz;
+#ifndef __NO_STRICT_ALIGNMENT
+               m_adj(mp, IGB_RXBUF_ALIGN);
+#endif
                /* Get the memory mapping */
                error = bus_dmamap_load_mbuf_sg(rxr->ptag,
                    rxbuf->pmap, mp, pseg, &nsegs, BUS_DMA_NOWAIT);
@@ -4291,6 +4301,9 @@
                mh = rxbuf->m_head;
                mh->m_len = mh->m_pkthdr.len = MHLEN;
                mh->m_flags |= M_PKTHDR;
+#ifndef __NO_STRICT_ALIGNMENT
+               m_adj(mh, IGB_RXBUF_ALIGN);
+#endif
                /* Get the memory mapping */
                error = bus_dmamap_load_mbuf_sg(rxr->htag,
                    rxbuf->hmap, rxbuf->m_head, hseg,
@@ -4312,6 +4325,9 @@
                }
                mp = rxbuf->m_pack;
                mp->m_pkthdr.len = mp->m_len = adapter->rx_mbuf_sz;
+#ifndef __NO_STRICT_ALIGNMENT
+               m_adj(mp, IGB_RXBUF_ALIGN);
+#endif
                /* Get the memory mapping */
                error = bus_dmamap_load_mbuf_sg(rxr->ptag,
                    rxbuf->pmap, mp, pseg,
@@ -4747,6 +4763,23 @@
        IGB_RX_LOCK(rxr);
 }

+#ifndef __NO_STRICT_ALIGNMENT
+static __inline void
+igb_fixup_rx(struct mbuf *m)
+{
+       int i;
+       uint16_t *src, *dst;
+
+       src = mtod(m, uint16_t *);
+       dst = src - (IGB_RXBUF_ALIGN - ETHER_ALIGN) / sizeof *src;
+
+       for (i = 0; i < (m->m_len / sizeof(uint16_t) + 1); i++)
+               *dst++ = *src++;
+
+       m->m_data -= IGB_RXBUF_ALIGN - ETHER_ALIGN;
+}
+#endif
+
 /*********************************************************************
  *
  *  This routine executes in interrupt context. It replenishes
@@ -4893,6 +4926,9 @@

                if (eop) {
                        rxr->fmp->m_pkthdr.rcvif = ifp;
+#ifndef __NO_STRICT_ALIGNMENT
+                       igb_fixup_rx(rxr->fmp);
+#endif
                        ifp->if_ipackets++;
                        rxr->rx_packets++;
                        /* capture data for AIM */

Maybe these patches  are of use for someone.

Regards,
Wolfgang Meyer


________________________________

Follow HOB:

- HOB: http://www.hob.de/redirect/hob.html
- Xing: http://www.hob.de/redirect/xing.html
- LinkedIn: http://www.hob.de/redirect/linkedin.html
- HOBLink Mobile: http://www.hob.de/redirect/hoblinkmobile.html
- Facebook: http://www.hob.de/redirect/facebook.html
- Twitter: http://www.hob.de/redirect/twitter.html
- YouTube: http://www.hob.de/redirect/youtube.html
- E-Mail: http://www.hob.de/redirect/mail.html


HOB GmbH & Co. KG
Schwadermuehlstr. 3
D-90556 Cadolzburg

Geschaeftsfuehrung: Klaus Brandstaetter, Zoran Adamovic

AG Fuerth, HRA 5180
Steuer-Nr. 218/163/00107
USt-ID-Nr. DE 132747002

Komplementaerin HOB electronic Beteiligungs GmbH
AG Fuerth, HRB 3416


More information about the freebsd-ia64 mailing list