On Mon, Feb 08, 2016 at 01:53:20PM +0100, Christian Ehrhardt wrote:
> 
> Hi everyone,
> 
> based on the latest release of the Intel driver for FreeBSD (em-7.5.2),
> I've adapted the em(4) driver to support the skylake based i219
> onboard ethernet chips.
> 
> I do not have access to relevant specs, everything below is
> based on reading the Intel code referenced above.
> 
> The diff was initially done for 5.7, bluhm@ did the forward port
> to current. The resulting diff is below.
> 
> The major differences are:
> - The NVRAM access registers are no longer in a separate BAR. Instead
>   they are at offset 0xe000 in the MMIO bar. As a consequence the
>   BAR access registers must be accessed with 32-Bit memory operations.
> - There are several quirks where the i219 chips need special handling.
> 
> The most suspicious one of the quirks is where we need to flush the
> tx desc ring. We use the pointer list of the tx ring as a send buffer
> for a dummy packet that must be sent to flush the tx ring.
> 
> Here's a list of functions that have special handling for the
> SPT based cards in the uptream intel code that I did not port
> for various reasons:
> - The link check code in OpenBSD differs significantly from upstream
>   code. Special cases for SPT based chips in em_check_for_link have
>   been ignored.
> - e1000_check_for_copper_link_ich8lan has been ignored.
> - e1000_suspend_workaroudns_ich8lan has been ignored. Suspend does
>   seem to work on my I219_V chip, though.
> - NVRAM write is not supported for I217 based chips in OpenBSD and
>   the code is missing for I219 chips, too.
> 
> The patch works nicely on my I219_V chip, the other chips are
> untested. I may be able to do tests with I219_LM withhin the next
> few days, though.
> 
> If you own a skylake based onboard NIC, please give this diff a try.
> 
> Who should I ask for oks?
> 
>      regards    Christian

some comments on this inline:

> 
> Index: dev/pci/if_em.c
> ===================================================================
> RCS file: /data/mirror/openbsd/cvs/src/sys/dev/pci/if_em.c,v
> retrieving revision 1.329
> diff -u -p -r1.329 if_em.c
> --- dev/pci/if_em.c   12 Jan 2016 00:05:21 -0000      1.329
> +++ dev/pci/if_em.c   4 Feb 2016 20:33:26 -0000
> @@ -145,6 +145,10 @@ const struct pci_matchid em_devices[] = 
>       { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_I218_V },
>       { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_I218_V_2 },
>       { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_I218_V_3 },
> +     { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_I219_LM },
> +     { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_I219_V },
> +     { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_I219_LM2 },
> +     { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_I219_V2 },
>       { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82580_COPPER },
>       { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82580_FIBER },
>       { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82580_SERDES },
> @@ -253,6 +257,9 @@ int  em_dma_malloc(struct em_softc *, bu
>  void em_dma_free(struct em_softc *, struct em_dma_alloc *);
>  u_int32_t em_fill_descriptors(u_int64_t address, u_int32_t length,
>                             PDESC_ARRAY desc_array);
> +void em_flush_tx_ring(struct em_softc *);
> +void em_flush_rx_ring(struct em_softc *);
> +void em_flush_desc_rings(struct em_softc *);
>  
>  /*********************************************************************
>   *  OpenBSD Device Interface Entry Points
> @@ -435,6 +442,7 @@ em_attach(struct device *parent, struct 
>               case em_ich10lan:
>               case em_pch2lan:
>               case em_pch_lpt:
> +             case em_pch_spt:
>               case em_80003es2lan:
>                       /* 9K Jumbo Frame size */
>                       sc->hw.max_frame_size = 9234;
> @@ -844,6 +852,7 @@ em_init(void *arg)
>       case em_pchlan:
>       case em_pch2lan:
>       case em_pch_lpt:
> +     case em_pch_spt:
>               pba = E1000_PBA_26K;
>               break;
>       default:
> @@ -1506,10 +1515,12 @@ em_stop(void *arg, int softonly)
>       timeout_del(&sc->timer_handle);
>       timeout_del(&sc->tx_fifo_timer_handle);
>  
> -     if (!softonly) {
> +     if (!softonly)
>               em_disable_intr(sc);
> +     if (sc->hw.mac_type == em_pch_spt)
> +             em_flush_desc_rings(sc);
> +     if (!softonly)
>               em_reset_hw(&sc->hw);
> -     }
>  
>       intr_barrier(sc->sc_intrhand);
>       ifq_barrier(&ifp->if_snd);
> @@ -1563,6 +1574,27 @@ em_identify_hardware(struct em_softc *sc
>               sc->hw.phy_init_script = TRUE;
>  }
>  
> +void
> +em_legacy_irq_quirk_spt(struct em_softc *sc)
> +{
> +     uint32_t        reg;
> +
> +     /* Legacy interrupt: SPT needs a quirk. */
> +     if (sc->hw.mac_type != em_pch_spt)
> +             return;
> +     if (sc->legacy_irq == 0)
> +             return;
> +
> +     reg = EM_READ_REG(&sc->hw, E1000_FEXTNVM7);
> +     reg |= E1000_FEXTNVM7_SIDE_CLK_UNGATE;
> +     EM_WRITE_REG(&sc->hw, E1000_FEXTNVM7, reg);
> +
> +     reg = EM_READ_REG(&sc->hw, E1000_FEXTNVM9);
> +     reg |= E1000_FEXTNVM9_IOSFSB_CLKGATE_DIS |
> +         E1000_FEXTNVM9_IOSFSB_CLKREQ_DIS;
> +     EM_WRITE_REG(&sc->hw, E1000_FEXTNVM9, reg);
> +}
> +
>  int
>  em_allocate_pci_resources(struct em_softc *sc)
>  {
> @@ -1617,8 +1649,15 @@ em_allocate_pci_resources(struct em_soft
>               break;
>       }
>  
> +     sc->osdep.em_flashoffset = 0;
>       /* for ICH8 and family we need to find the flash memory */
> -     if (IS_ICH8(sc->hw.mac_type)) {
> +     if (sc->hw.mac_type == em_pch_spt) {
> +             sc->osdep.flash_bus_space_tag = sc->osdep.mem_bus_space_tag;
> +             sc->osdep.flash_bus_space_handle = 
> sc->osdep.mem_bus_space_handle;
> +             sc->osdep.em_flashbase = 0;
> +             sc->osdep.em_flashsize = 0;
> +             sc->osdep.em_flashoffset = 0xe000;
> +     } else if (IS_ICH8(sc->hw.mac_type)) {
>               val = pci_conf_read(pa->pa_pc, pa->pa_tag, EM_FLASH);
>               if (PCI_MAPREG_TYPE(val) != PCI_MAPREG_TYPE_MEM) {
>                       printf(": flash is not mem space\n");
> @@ -1633,9 +1672,13 @@ em_allocate_pci_resources(struct em_soft
>               }
>          }
>  
> -     if (pci_intr_map_msi(pa, &ih) && pci_intr_map(pa, &ih)) {
> -             printf(": couldn't map interrupt\n");
> -             return (ENXIO);
> +     sc->legacy_irq = 0;
> +     if (pci_intr_map_msi(pa, &ih)) {
> +             if (pci_intr_map(pa, &ih)) {
> +                     printf(": couldn't map interrupt\n");
> +                     return (ENXIO);
> +             }
> +             sc->legacy_irq = 1;
>       }
>  
>       sc->osdep.dev = (struct device *)sc;
> @@ -1717,6 +1760,8 @@ em_hardware_init(struct em_softc *sc)
>       u_int16_t rx_buffer_size;
>  
>       INIT_DEBUGOUT("em_hardware_init: begin");
> +     if (sc->hw.mac_type == em_pch_spt)
> +             em_flush_desc_rings(sc);
>       /* Issue a global reset */
>       em_reset_hw(&sc->hw);
>  
> @@ -1761,6 +1806,8 @@ em_hardware_init(struct em_softc *sc)
>               em_write_phy_reg(&sc->hw, IGP02E1000_PHY_POWER_MGMT, phy_tmp);
>       }
>  
> +     em_legacy_irq_quirk_spt(sc);
> +
>       /*
>        * These parameters control the automatic generation (Tx) and 
>        * response (Rx) to Ethernet PAUSE frames.
> @@ -2189,6 +2236,20 @@ em_initialize_transmit_unit(struct em_so
>               reg_tctl |= E1000_HDX_COLLISION_DISTANCE << E1000_COLD_SHIFT;
>       /* This write will effectively turn on the transmit unit */
>       E1000_WRITE_REG(&sc->hw, TCTL, reg_tctl);
> +
> +     /* SPT Si errata workaround to avoid data corruption */
> +
> +     if (sc->hw.mac_type == em_pch_spt) {
> +             uint32_t        reg_val;
> +
> +             reg_val = EM_READ_REG(&sc->hw, E1000_IOSFPC);
> +             reg_val |= E1000_RCTL_RDMTS_HEX;
> +             EM_WRITE_REG(&sc->hw, E1000_IOSFPC, reg_val);
> +
> +             reg_val = E1000_READ_REG(&sc->hw, TARC0);
> +             reg_val |= (1U << 28 | 1U << 29);

This shouldn't be magic numbers, in the Intel code in FreeBSD it is:

|= E1000_TARC0_CB_MULTIQ_3_REQ

> +             E1000_WRITE_REG(&sc->hw, TARC0, reg_val);
> +     }
>  }
>  
>  /*********************************************************************
> @@ -3066,6 +3127,95 @@ em_disable_aspm(struct em_softc *sc)
>  
>       pci_conf_write(sc->osdep.em_pa.pa_pc, sc->osdep.em_pa.pa_tag,
>           offset + PCI_PCIE_LCSR, val);
> +}
> +

add the comment from the Intel code here

> +void
> +em_flush_tx_ring(struct em_softc *sc)
> +{
> +     uint32_t                 tctl, txd_lower = E1000_TXD_CMD_IFCS;
> +     uint16_t                 size = 512;
> +     struct em_tx_desc       *txd;
> +     uint64_t                 addr;
> +
> +     KASSERT(sc->sc_tx_desc_ring != NULL);
> +
> +     tctl = EM_READ_REG(&sc->hw, E1000_TCTL);
> +     EM_WRITE_REG(&sc->hw, E1000_TCTL, tctl | E1000_TCTL_EN);
> +
> +     KASSERT(EM_READ_REG(&sc->hw, E1000_TDT) == sc->sc_tx_desc_head);
> +
> +     addr = E1000_READ_REG(&sc->hw, TDBAH);
> +     addr <<= 32;
> +     addr |= E1000_READ_REG(&sc->hw, TDBAL);
> +
> +     txd = &sc->sc_tx_desc_ring[sc->sc_tx_desc_head];
> +     txd->buffer_addr = addr;

Isn't addr just sc->sc_tx_dma.dma_map->dm_segs[0].ds_addr ?
Do we really need to ask the hardware for it here?

> +     txd->lower.data = htole32(txd_lower | size);
> +     txd->upper.data = 0;
> +
> +     /* flush descriptors to memory before notifying the HW */
> +     bus_space_barrier(sc->osdep.mem_bus_space_tag,
> +         sc->osdep.mem_bus_space_handle, 0, 0, BUS_SPACE_BARRIER_WRITE);
> +
> +     if (++sc->sc_tx_desc_head == sc->sc_tx_slots)
> +             sc->sc_tx_desc_head = 0;
> +
> +     EM_WRITE_REG(&sc->hw, E1000_TDT, sc->sc_tx_desc_head);
> +     bus_space_barrier(sc->osdep.mem_bus_space_tag, 
> sc->osdep.mem_bus_space_handle,
> +         0, 0, BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE);
> +     usec_delay(500);

this delay is only 250 in FreeBSD

> +}
> +
> +void
> +em_flush_rx_ring(struct em_softc *sc)
> +{
> +     uint32_t        rctl, rxdctl;
> +
> +     rctl = EM_READ_REG(&sc->hw, E1000_RCTL);
> +     EM_WRITE_REG(&sc->hw, E1000_RCTL, rctl & ~E1000_RCTL_EN);
> +     E1000_WRITE_FLUSH(&sc->hw);
> +     usec_delay(150);
> +
> +     rxdctl = EM_READ_REG(&sc->hw, E1000_RXDCTL);
> +     /* zero the lower 14 bits (prefetch and host thresholds) */
> +     rxdctl &= 0xffffc000;
> +     /*
> +      * update thresholds: prefetch threshold to 31, host threshold to 1
> +      * and make sure the granularity is "descriptors" and not "cache lines"
> +      */
> +     rxdctl |= (0x1F | (1 << 8) | E1000_RXDCTL_THRESH_UNIT_DESC);
> +
> +     /* momentarily enable the RX ring for the changes to take effect */
> +     EM_WRITE_REG(&sc->hw, E1000_RXDCTL, rxdctl);

This write should be above the comment to match the Intel code.

> +     EM_WRITE_REG(&sc->hw, E1000_RCTL, rctl | E1000_RCTL_EN);
> +     E1000_WRITE_FLUSH(&sc->hw);
> +     usec_delay(150);
> +     EM_WRITE_REG(&sc->hw, E1000_RCTL, rctl & ~E1000_RCTL_EN);
> +}
> +

comment here as well

> +void
> +em_flush_desc_rings(struct em_softc *sc)
> +{
> +     struct pci_attach_args  *pa = &sc->osdep.em_pa;
> +     uint32_t                 fextnvm11, tdlen;
> +     uint16_t                 hang_state;
> +
> +     /* First, disable MULR fix in FEXTNVM11 */
> +     fextnvm11 = EM_READ_REG(&sc->hw, E1000_FEXTNVM11);
> +     fextnvm11 |= E1000_FEXTNVM11_DISABLE_MULR_FIX;
> +     EM_WRITE_REG(&sc->hw, E1000_FEXTNVM11, fextnvm11);
> +
> +     /* do nothing if we're not in faulty state, or if the queue is empty */
> +     tdlen = EM_READ_REG(&sc->hw, E1000_TDLEN);
> +     hang_state = pci_conf_read(pa->pa_pc, pa->pa_tag, 
> PCICFG_DESC_RING_STATUS);
> +     if (!(hang_state & FLUSH_DESC_REQUIRED) || !tdlen)
> +             return;
> +     em_flush_tx_ring(sc);
> +
> +     /* recheck, maybe the fault is caused by the rx ring */
> +     hang_state = pci_conf_read(pa->pa_pc, pa->pa_tag, 
> PCICFG_DESC_RING_STATUS);
> +     if (hang_state & FLUSH_DESC_REQUIRED)
> +             em_flush_rx_ring(sc);
>  }
>  
>  #ifndef SMALL_KERNEL
> Index: dev/pci/if_em.h
> ===================================================================
> RCS file: /data/mirror/openbsd/cvs/src/sys/dev/pci/if_em.h,v
> retrieving revision 1.71
> diff -u -p -r1.71 if_em.h
> --- dev/pci/if_em.h   11 Jan 2016 01:31:53 -0000      1.71
> +++ dev/pci/if_em.h   4 Feb 2016 14:39:02 -0000
> @@ -230,6 +230,9 @@ typedef int       boolean_t;
>  
>  #define MAX_NUM_MULTICAST_ADDRESSES  128
>  
> +#define PCICFG_DESC_RING_STATUS              0xe4
> +#define FLUSH_DESC_REQUIRED          0x100
> +
>  /*
>   * TDBA/RDBA should be aligned on 16 byte boundary. But TDLEN/RDLEN should be
>   * multiple of 128 bytes. So we align TDBA/RDBA on 128 byte boundary. This 
> will
> @@ -319,6 +322,7 @@ struct em_softc {
>       struct em_osdep osdep;
>       struct ifmedia  media;
>       int             io_rid;
> +     int             legacy_irq;
>  
>       void            *sc_intrhand;
>       struct timeout  em_intr_enable;
> Index: dev/pci/if_em_hw.c
> ===================================================================
> RCS file: /data/mirror/openbsd/cvs/src/sys/dev/pci/if_em_hw.c,v
> retrieving revision 1.90
> diff -u -p -r1.90 if_em_hw.c
> --- dev/pci/if_em_hw.c        14 Dec 2015 03:04:10 -0000      1.90
> +++ dev/pci/if_em_hw.c        4 Feb 2016 14:39:02 -0000
> @@ -106,6 +106,7 @@ static int32_t    em_read_ich8_byte(struct 
>  static int32_t       em_verify_write_ich8_byte(struct em_hw *, uint32_t, 
> uint8_t);
>  static int32_t       em_write_ich8_byte(struct em_hw *, uint32_t, uint8_t);
>  static int32_t       em_read_ich8_word(struct em_hw *, uint32_t, uint16_t *);
> +static int32_t       em_read_ich8_dword(struct em_hw *, uint32_t, uint32_t 
> *);
>  static int32_t       em_read_ich8_data(struct em_hw *, uint32_t, uint32_t,
>                   uint16_t *);
>  static int32_t       em_write_ich8_data(struct em_hw *, uint32_t, uint32_t,
> @@ -610,6 +611,12 @@ em_set_mac_type(struct em_hw *hw)
>       case E1000_DEV_ID_PCH_I218_V3:
>               hw->mac_type = em_pch_lpt;
>               break;
> +     case E1000_DEV_ID_PCH_SPT_I219_LM:
> +     case E1000_DEV_ID_PCH_SPT_I219_V:
> +     case E1000_DEV_ID_PCH_SPT_I219_LM2:
> +     case E1000_DEV_ID_PCH_SPT_I219_V2:
> +             hw->mac_type = em_pch_spt;
> +             break;
>       case E1000_DEV_ID_EP80579_LAN_1:
>               hw->mac_type = em_icp_xxxx;
>               hw->icp_xxxx_port_num = 0;
> @@ -640,6 +647,7 @@ em_set_mac_type(struct em_hw *hw)
>       case em_pchlan:
>       case em_pch2lan:
>       case em_pch_lpt:
> +     case em_pch_spt:
>               hw->swfwhw_semaphore_present = TRUE;
>               hw->asf_firmware_present = TRUE;
>               break;
> @@ -736,6 +744,7 @@ em_set_media_type(struct em_hw *hw)
>               case em_pchlan:
>               case em_pch2lan:
>               case em_pch_lpt:
> +             case em_pch_spt:
>               case em_82573:
>               case em_82574:
>                       /*
> @@ -893,6 +902,7 @@ em_reset_hw(struct em_hw *hw)
>       case em_pchlan:
>       case em_pch2lan:
>       case em_pch_lpt:
> +     case em_pch_spt:
>               if (!hw->phy_reset_disable &&
>                   em_check_phy_reset_block(hw) == E1000_SUCCESS) {
>                       /*
> @@ -1141,6 +1151,7 @@ em_initialize_hardware_bits(struct em_hw
>               case em_pchlan:
>               case em_pch2lan:
>               case em_pch_lpt:
> +             case em_pch_spt:
>                       if (hw->mac_type == em_ich8lan)
>                               /* Set TARC0 bits 29 and 28 */
>                               reg_tarc0 |= 0x30000000;
> @@ -1215,7 +1226,8 @@ em_init_hw(struct em_hw *hw)
>  
>       if (hw->mac_type == em_pchlan ||
>               hw->mac_type == em_pch2lan ||
> -             hw->mac_type == em_pch_lpt) {
> +             hw->mac_type == em_pch_lpt ||
> +             hw->mac_type == em_pch_spt) {
>               /*
>                * The MAC-PHY interconnect may still be in SMBus mode
>                * after Sx->S0.  Toggle the LANPHYPC Value bit to force
> @@ -1426,6 +1438,7 @@ em_init_hw(struct em_hw *hw)
>       case em_pchlan:
>       case em_pch2lan:
>       case em_pch_lpt:
> +     case em_pch_spt:
>               ctrl = E1000_READ_REG(hw, TXDCTL1);
>               ctrl = (ctrl & ~E1000_TXDCTL_WTHRESH) | 
>                   E1000_TXDCTL_FULL_TX_DESC_WB;
> @@ -1557,6 +1570,7 @@ em_setup_link(struct em_hw *hw)
>               case em_pchlan:
>               case em_pch2lan:
>               case em_pch_lpt:
> +             case em_pch_spt:
>               case em_82573:
>               case em_82574:
>                       hw->fc = E1000_FC_FULL;
> @@ -2007,7 +2021,8 @@ em_copper_link_igp_setup(struct em_hw *h
>       /* disable lplu d0 during driver init */
>       if (hw->mac_type == em_pchlan ||
>               hw->mac_type == em_pch2lan ||
> -             hw->mac_type == em_pch_lpt)
> +             hw->mac_type == em_pch_lpt ||
> +             hw->mac_type == em_pch_spt)
>               ret_val = em_set_lplu_state_pchlan(hw, FALSE);
>       else
>               ret_val = em_set_d0_lplu_state(hw, FALSE);
> @@ -2279,7 +2294,8 @@ em_copper_link_mgp_setup(struct em_hw *h
>       /* disable lplu d0 during driver init */
>       if (hw->mac_type == em_pchlan ||
>               hw->mac_type == em_pch2lan ||
> -             hw->mac_type == em_pch_lpt)
> +             hw->mac_type == em_pch_lpt ||
> +             hw->mac_type == em_pch_spt)
>               ret_val = em_set_lplu_state_pchlan(hw, FALSE);
>  
>       /* Enable CRS on TX. This must be set for half-duplex operation. */
> @@ -2750,6 +2766,7 @@ em_setup_copper_link(struct em_hw *hw)
>       case em_pchlan:
>       case em_pch2lan:
>       case em_pch_lpt:
> +     case em_pch_spt:
>               /*
>                * Set the mac to wait the maximum time between each
>                * iteration and increase the max iterations when polling the
> @@ -3917,7 +3934,8 @@ em_check_for_link(struct em_hw *hw)
>  
>                       /* Enable/Disable EEE after link up */
>                       if (hw->mac_type == em_pch2lan ||
> -                         hw->mac_type == em_pch_lpt) {
> +                         hw->mac_type == em_pch_lpt ||
> +                         hw->mac_type == em_pch_spt) {
>                               ret_val = em_set_eee_pchlan(hw);
>                               if (ret_val)
>                                       return ret_val;
> @@ -4702,7 +4720,8 @@ em_read_phy_reg(struct em_hw *hw, uint32
>  
>       if (hw->mac_type == em_pchlan ||
>               hw->mac_type == em_pch2lan ||
> -             hw->mac_type == em_pch_lpt)
> +             hw->mac_type == em_pch_lpt ||
> +             hw->mac_type == em_pch_spt)
>               return (em_access_phy_reg_hv(hw, reg_addr, phy_data, TRUE));
>  
>       if (((hw->mac_type == em_80003es2lan) || (hw->mac_type == em_82575)) &&
> @@ -4815,7 +4834,7 @@ em_read_phy_reg_ex(struct em_hw *hw, uin
>               }
>               *phy_data = (uint16_t) mdic;
>  
> -             if (hw->mac_type == em_pch2lan || hw->mac_type == em_pch_lpt)
> +             if (hw->mac_type == em_pch2lan || hw->mac_type == em_pch_lpt || 
> hw->mac_type == em_pch_spt)
>                       usec_delay(100);
>       } else {
>               /*
> @@ -4866,7 +4885,8 @@ em_write_phy_reg(struct em_hw *hw, uint3
>  
>       if (hw->mac_type == em_pchlan ||
>               hw->mac_type == em_pch2lan ||
> -             hw->mac_type == em_pch_lpt)
> +             hw->mac_type == em_pch_lpt ||
> +             hw->mac_type == em_pch_spt)
>               return (em_access_phy_reg_hv(hw, reg_addr, &phy_data, FALSE));
>  
>       if (em_swfw_sync_acquire(hw, hw->swfw))
> @@ -4966,7 +4986,7 @@ em_write_phy_reg_ex(struct em_hw *hw, ui
>                       return -E1000_ERR_PHY;
>               }
>  
> -             if (hw->mac_type == em_pch2lan || hw->mac_type == em_pch_lpt)
> +             if (hw->mac_type == em_pch2lan || hw->mac_type == em_pch_lpt || 
> hw->mac_type == em_pch_spt)
>                       usec_delay(100);
>       } else {
>               /*
> @@ -5455,6 +5475,7 @@ em_match_gig_phy(struct em_hw *hw)
>                       match = TRUE;
>               break;
>       case em_pch_lpt:
> +     case em_pch_spt:
>               if (hw->phy_id == I217_E_PHY_ID)
>                       match = TRUE;
>               break;

Odd that I219 advertises itself as I217

> @@ -5783,6 +5804,33 @@ em_init_eeprom_params(struct em_hw *hw)
>  
>                       break;
>               }
> +     case em_pch_spt:
> +             {
> +                     int32_t         i = 0;
> +                     uint32_t        flash_size = EM_READ_REG(hw, 0xc /* 
> STRAP */);
> +
> +                     eeprom->type = em_eeprom_ich8;
> +                     eeprom->use_eerd = FALSE;
> +                     eeprom->use_eewr = FALSE;
> +                     eeprom->word_size = E1000_SHADOW_RAM_WORDS;
> +                     /*
> +                      * Zero the shadow RAM structure. But don't load it
> +                      * from NVM so as to save time for driver init
> +                      */
> +                     if (hw->eeprom_shadow_ram != NULL) {
> +                             for (i = 0; i < E1000_SHADOW_RAM_WORDS; i++) {
> +                                     hw->eeprom_shadow_ram[i].modified = 
> +                                         FALSE;
> +                                     hw->eeprom_shadow_ram[i].eeprom_word = 
> +                                         0xFFFF;
> +                             }
> +                     }
> +                     hw->flash_base_addr = 0;
> +                     flash_size = ((flash_size >> 1) & 0x1f) + 1;
> +                     flash_size *= 4096;
> +                     hw->flash_bank_size = flash_size / 4;
> +             }
> +             break;
>       default:
>               break;
>       }
> @@ -6470,6 +6518,7 @@ em_validate_eeprom_checksum(struct em_hw
>                */
>               switch (hw->mac_type) {
>               case em_pch_lpt:
> +             case em_pch_spt:
>                       word = EEPROM_COMPAT;
>                       valid_csum_mask = EEPROM_COMPAT_VALID_CSUM;
>                       break;
> @@ -6813,6 +6862,7 @@ em_commit_shadow_ram(struct em_hw *hw)
>                       return -E1000_ERR_EEPROM;
>               }
>       }
> +     /* XXX CEH: Some code for eeprom write is missing. */

not sure this comment is needed

>       if ((hw->mac_type == em_ich8lan || hw->mac_type == em_ich9lan) &&
>           hw->eeprom_shadow_ram != NULL) {
>               /*
> @@ -7131,7 +7181,7 @@ em_init_rx_addrs(struct em_hw *hw)
>       uint32_t rar_num;
>       DEBUGFUNC("em_init_rx_addrs");
>  
> -     if (hw->mac_type == em_pch_lpt || hw->mac_type == em_pch2lan)
> +     if (hw->mac_type == em_pch_lpt || hw->mac_type == em_pch_spt || 
> hw->mac_type == em_pch2lan)
>               if (em_phy_no_cable_workaround(hw))
>                       printf(" ...failed to apply em_phy_no_cable_"
>                           "workaround.\n");
> @@ -7688,7 +7738,7 @@ em_clear_hw_cntrs(struct em_hw *hw)
>           hw->mac_type == em_ich9lan ||
>           hw->mac_type == em_ich10lan ||
>           hw->mac_type == em_pchlan ||
> -         (hw->mac_type != em_pch2lan && hw->mac_type != em_pch_lpt))
> +         (hw->mac_type != em_pch2lan && hw->mac_type != em_pch_lpt && 
> hw->mac_type != em_pch_spt))
>               return;
>  
>       temp = E1000_READ_REG(hw, ICRXPTC);
> @@ -7830,6 +7880,7 @@ em_get_bus_info(struct em_hw *hw)
>       case em_pchlan:
>       case em_pch2lan:
>       case em_pch_lpt:
> +     case em_pch_spt:
>               hw->bus_type = em_bus_type_pci_express;
>               hw->bus_speed = em_bus_speed_2500;
>               hw->bus_width = em_bus_width_pciex_1;
> @@ -9022,6 +9073,7 @@ em_get_auto_rd_done(struct em_hw *hw)
>       case em_pchlan:
>       case em_pch2lan:
>       case em_pch_lpt:
> +     case em_pch_spt:
>               while (timeout) {
>                       if (E1000_READ_REG(hw, EECD) & E1000_EECD_AUTO_RD)
>                               break;
> @@ -9380,12 +9432,45 @@ em_valid_nvm_bank_detect_ich8lan(struct 
>       uint32_t eecd;
>       uint32_t bank1_offset = hw->flash_bank_size * sizeof(uint16_t);
>       uint32_t act_offset = E1000_ICH_NVM_SIG_WORD * 2 + 1;
> +     uint32_t nvm_dword = 0;
>       uint8_t sig_byte = 0;
>       int32_t ret_val;
>  
>       DEBUGFUNC("em_valid_nvm_bank_detect_ich8lan");
>  
>       switch (hw->mac_type) {
> +     case em_pch_spt:
> +             bank1_offset = hw->flash_bank_size * 2;
> +             act_offset = E1000_ICH_NVM_SIG_WORD * 2;
> +
> +             /* set bank to 0 in case flash read fails. */
> +             *bank = 0;
> +
> +             /* Check bank 0 */
> +             ret_val = em_read_ich8_dword(hw, act_offset, &nvm_dword);
> +             if (ret_val)
> +                     return ret_val;
> +             sig_byte = (uint8_t)((nvm_dword & 0xFF00) >> 8);
> +             if ((sig_byte & E1000_ICH_NVM_VALID_SIG_MASK) ==
> +                 E1000_ICH_NVM_SIG_VALUE) {
> +                     *bank = 0;
> +                     return 0;
> +             }
> +
> +             /* Check bank 1 */
> +             ret_val = em_read_ich8_dword(hw, act_offset + bank1_offset,
> +                 &nvm_dword);
> +             if (ret_val)
> +                     return ret_val;
> +             sig_byte = (uint8_t)((nvm_dword & 0xFF00) >> 8);
> +             if ((sig_byte & E1000_ICH_NVM_VALID_SIG_MASK) ==
> +                 E1000_ICH_NVM_SIG_VALUE) {
> +                     *bank = 1;
> +                     return 0;
> +             }
> +
> +             DEBUGOUT("ERROR: No valid NVM bank present\n");
> +             return -1;
>       case em_ich8lan:
>       case em_ich9lan:
>               eecd = E1000_READ_REG(hw, EECD);
> @@ -9432,6 +9517,92 @@ em_valid_nvm_bank_detect_ich8lan(struct 
>       }
>  }
>  
> +STATIC int32_t
> +em_read_eeprom_spt(struct em_hw *hw, uint16_t offset, uint16_t words,
> +    uint16_t *data)
> +{
> +     int32_t  error = E1000_SUCCESS;
> +     uint32_t flash_bank = 0;
> +     uint32_t act_offset = 0;
> +     uint32_t bank_offset = 0;
> +     uint32_t dword = 0;
> +     uint16_t i = 0, add;
> +
> +     /*
> +      * We need to know which is the valid flash bank.  In the event that
> +      * we didn't allocate eeprom_shadow_ram, we may not be managing
> +      * flash_bank.  So it cannot be trusted and needs to be updated with
> +      * each read.
> +      */
> +
> +     if (hw->mac_type != em_pch_spt)
> +             return -E1000_ERR_EEPROM;
> +
> +     error = em_get_software_flag(hw);
> +     if (error != E1000_SUCCESS)
> +             return error;
> +
> +     error = em_valid_nvm_bank_detect_ich8lan(hw, &flash_bank);
> +     if (error != E1000_SUCCESS) {
> +             DEBUGOUT("Could not detect valid bank, assuming bank 0\n");
> +             flash_bank = 0;
> +     }
> +
> +     /*
> +      * Adjust offset appropriately if we're on bank 1 - adjust for word
> +      * size
> +      */
> +     bank_offset = flash_bank * (hw->flash_bank_size * 2);
> +
> +     for (i = add = 0; i < words; i += add) {
> +             if ((offset + i) % 2) {
> +                     add = 1;
> +                     if (hw->eeprom_shadow_ram != NULL
> +                         && hw->eeprom_shadow_ram[offset + i].modified) {
> +                             data[i] =
> +                                 hw->eeprom_shadow_ram[offset+i].eeprom_word;
> +                             continue;
> +                     }
> +                     act_offset = bank_offset + (offset + i - 1) * 2;
> +             } else {
> +                     add = 2;
> +                     if (hw->eeprom_shadow_ram != NULL
> +                         && hw->eeprom_shadow_ram[offset+i].modified
> +                         && hw->eeprom_shadow_ram[offset+i+1].modified) {
> +                             data[i] = 
> hw->eeprom_shadow_ram[offset+i].eeprom_word;
> +                             data[i+1] = 
> hw->eeprom_shadow_ram[offset+i+1].eeprom_word;
> +                             continue;
> +                     }
> +                     act_offset = bank_offset + (offset + i) * 2;
> +             }
> +             error = em_read_ich8_dword(hw, act_offset, &dword);
> +             if (error != E1000_SUCCESS)
> +                     break;
> +             if (hw->eeprom_shadow_ram != NULL
> +                 && hw->eeprom_shadow_ram[offset+i].modified) {
> +                     data[i] = hw->eeprom_shadow_ram[offset+i].eeprom_word;
> +             } else {
> +                     if (add == 1)
> +                             data[i] = dword >> 16;
> +                     else
> +                             data[i] = dword & 0xFFFFUL;
> +             }
> +             if (add == 1 || words-i == 1)
> +                     continue;
> +             if (hw->eeprom_shadow_ram != NULL
> +                 && hw->eeprom_shadow_ram[offset+i+1].modified) {
> +                     data[i+1] =
> +                         hw->eeprom_shadow_ram[offset+i+1].eeprom_word;
> +             } else {
> +                     data[i+1] = dword >> 16;
> +             }
> +     }
> +
> +     em_release_software_flag(hw);
> +
> +     return error;
> +}
> +
>  
> /******************************************************************************
>   * Reads a 16 bit word or words from the EEPROM using the ICH8's flash access
>   * register.
> @@ -9458,6 +9629,9 @@ em_read_eeprom_ich8(struct em_hw *hw, ui
>        * each read.
>        */
>  
> +     if (hw->mac_type == em_pch_spt)
> +             return em_read_eeprom_spt(hw, offset, words, data);
> +
>       error = em_get_software_flag(hw);
>       if (error != E1000_SUCCESS)
>               return error;
> @@ -9562,7 +9736,12 @@ em_ich8_cycle_init(struct em_hw *hw)
>       int32_t i = 0;
>       DEBUGFUNC("em_ich8_cycle_init");
>  
> -     hsfsts.regval = E1000_READ_ICH_FLASH_REG16(hw, ICH_FLASH_HSFSTS);
> +     if (hw->mac_type == em_pch_spt)
> +             hsfsts.regval = E1000_READ_ICH_FLASH_REG32(hw,
> +                 ICH_FLASH_HSFSTS) & 0xFFFFUL;
> +     else
> +             hsfsts.regval = E1000_READ_ICH_FLASH_REG16(hw,
> +                 ICH_FLASH_HSFSTS);
>  
>       /* May be check the Flash Des Valid bit in Hw status */
>       if (hsfsts.hsf_status.fldesvalid == 0) {
> @@ -9574,8 +9753,12 @@ em_ich8_cycle_init(struct em_hw *hw)
>       /* Clear DAEL in Hw status by writing a 1 */
>       hsfsts.hsf_status.flcerr = 1;
>       hsfsts.hsf_status.dael = 1;
> -
> -     E1000_WRITE_ICH_FLASH_REG16(hw, ICH_FLASH_HSFSTS, hsfsts.regval);
> +     if (hw->mac_type == em_pch_spt)
> +             E1000_WRITE_ICH_FLASH_REG32(hw, ICH_FLASH_HSFSTS,
> +                 hsfsts.regval & 0xFFFFUL);
> +     else
> +             E1000_WRITE_ICH_FLASH_REG16(hw, ICH_FLASH_HSFSTS,
> +                 hsfsts.regval);
>       /*
>        * Either we should have a hardware SPI cycle in progress bit to
>        * check against, in order to start a new cycle or FDONE bit should
> @@ -9595,8 +9778,12 @@ em_ich8_cycle_init(struct em_hw *hw)
>                */
>               /* Begin by setting Flash Cycle Done. */
>               hsfsts.hsf_status.flcdone = 1;
> -             E1000_WRITE_ICH_FLASH_REG16(hw, ICH_FLASH_HSFSTS,
> -                 hsfsts.regval);
> +             if (hw->mac_type == em_pch_spt)
> +                     E1000_WRITE_ICH_FLASH_REG32(hw, ICH_FLASH_HSFSTS,
> +                         hsfsts.regval & 0xFFFFUL);
> +             else
> +                     E1000_WRITE_ICH_FLASH_REG16(hw, ICH_FLASH_HSFSTS,
> +                         hsfsts.regval);
>               error = E1000_SUCCESS;
>       } else {
>               /*
> @@ -9604,8 +9791,12 @@ em_ich8_cycle_init(struct em_hw *hw)
>                * chance to end before giving up.
>                */
>               for (i = 0; i < ICH_FLASH_COMMAND_TIMEOUT; i++) {
> -                     hsfsts.regval = E1000_READ_ICH_FLASH_REG16(hw,
> -                         ICH_FLASH_HSFSTS);
> +                     if (hw->mac_type == em_pch_spt)
> +                             hsfsts.regval = E1000_READ_ICH_FLASH_REG32(
> +                                 hw, ICH_FLASH_HSFSTS) & 0xFFFFUL;
> +                     else
> +                             hsfsts.regval = E1000_READ_ICH_FLASH_REG16(
> +                                 hw, ICH_FLASH_HSFSTS);
>                       if (hsfsts.hsf_status.flcinprog == 0) {
>                               error = E1000_SUCCESS;
>                               break;
> @@ -9618,8 +9809,12 @@ em_ich8_cycle_init(struct em_hw *hw)
>                        * timeout, now set the Flash Cycle Done.
>                        */
>                       hsfsts.hsf_status.flcdone = 1;
> -                     E1000_WRITE_ICH_FLASH_REG16(hw, ICH_FLASH_HSFSTS,
> -                         hsfsts.regval);
> +                     if (hw->mac_type == em_pch_spt)
> +                             E1000_WRITE_ICH_FLASH_REG32(hw,
> +                                 ICH_FLASH_HSFSTS, hsfsts.regval & 0xFFFFUL);
> +                     else
> +                             E1000_WRITE_ICH_FLASH_REG16(hw,
> +                                 ICH_FLASH_HSFSTS, hsfsts.regval);
>               } else {
>                       DEBUGOUT("Flash controller busy, cannot get access");
>               }
> @@ -9639,15 +9834,31 @@ em_ich8_flash_cycle(struct em_hw *hw, ui
>       union ich8_hws_flash_status hsfsts;
>       int32_t  error = E1000_ERR_EEPROM;
>       uint32_t i = 0;
> +
>       /* Start a cycle by writing 1 in Flash Cycle Go in Hw Flash Control */
> -     hsflctl.regval = E1000_READ_ICH_FLASH_REG16(hw, ICH_FLASH_HSFCTL);
> +     if (hw->mac_type == em_pch_spt)
> +             hsflctl.regval = E1000_READ_ICH_FLASH_REG32(hw,
> +                 ICH_FLASH_HSFSTS) >> 16;
> +     else
> +             hsflctl.regval = E1000_READ_ICH_FLASH_REG16(hw,
> +                 ICH_FLASH_HSFCTL);
>       hsflctl.hsf_ctrl.flcgo = 1;
> -     E1000_WRITE_ICH_FLASH_REG16(hw, ICH_FLASH_HSFCTL, hsflctl.regval);
> +
> +     if (hw->mac_type == em_pch_spt)
> +             E1000_WRITE_ICH_FLASH_REG32(hw, ICH_FLASH_HSFSTS,
> +                 (uint32_t)hsflctl.regval << 16);
> +     else
> +             E1000_WRITE_ICH_FLASH_REG16(hw, ICH_FLASH_HSFCTL,
> +                 hsflctl.regval);
>  
>       /* wait till FDONE bit is set to 1 */
>       do {
> -             hsfsts.regval = E1000_READ_ICH_FLASH_REG16(hw,
> -                 ICH_FLASH_HSFSTS);
> +             if (hw->mac_type == em_pch_spt)
> +                     hsfsts.regval = E1000_READ_ICH_FLASH_REG32(hw,
> +                         ICH_FLASH_HSFSTS) & 0xFFFFUL;
> +             else
> +                     hsfsts.regval = E1000_READ_ICH_FLASH_REG16(hw,
> +                         ICH_FLASH_HSFSTS);
>               if (hsfsts.hsf_status.flcdone == 1)
>                       break;
>               usec_delay(1);
> @@ -9706,7 +9917,7 @@ em_read_ich8_data(struct em_hw *hw, uint
>                */
>               /* TODO: TBD maybe check the index against the size of flash */
>  
> -             E1000_WRITE_ICH_FLASH_REG(hw, ICH_FLASH_FADDR,
> +             E1000_WRITE_ICH_FLASH_REG32(hw, ICH_FLASH_FADDR,
>                   flash_linear_address);
>  
>               error = em_ich8_flash_cycle(hw, ICH_FLASH_COMMAND_TIMEOUT);
> @@ -9748,11 +9959,88 @@ em_read_ich8_data(struct em_hw *hw, uint
>       return error;
>  }

The latest Intel code in FreeBSD passes size as an argument to
this function.  Should ours do the same?

>  
> +STATIC int32_t
> +em_read_ich8_data32(struct em_hw *hw, uint32_t offset, uint32_t *data)
> +{
> +     union ich8_hws_flash_status hsfsts;
> +     union ich8_hws_flash_ctrl hsflctl;
> +     uint32_t flash_linear_address;
> +     int32_t  error = -E1000_ERR_EEPROM;
> +     uint32_t  count = 0;
> +     DEBUGFUNC("em_read_ich8_data32");
> +
> +     if (hw->mac_type != em_pch_spt)
> +             return error;
> +     if (offset > ICH_FLASH_LINEAR_ADDR_MASK)
> +             return error;
> +     flash_linear_address = (ICH_FLASH_LINEAR_ADDR_MASK & offset) +
> +         hw->flash_base_addr;
> +
> +     do {
> +             usec_delay(1);
> +             /* Steps */
> +             error = em_ich8_cycle_init(hw);
> +             if (error != E1000_SUCCESS)
> +                     break;
> +
> +             /* 32 bit accesses in SPT. */
> +             hsflctl.regval = E1000_READ_ICH_FLASH_REG32(hw,
> +                 ICH_FLASH_HSFSTS) >> 16;
> +
> +             hsflctl.hsf_ctrl.fldbcount = sizeof(uint32_t) - 1;
> +             hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_READ;
> +
> +             E1000_WRITE_ICH_FLASH_REG32(hw, ICH_FLASH_HSFSTS,
> +                 (uint32_t)hsflctl.regval << 16);
> +             /*
> +              * Write the last 24 bits of offset into Flash Linear address
> +              * field in Flash Address
> +              */
> +             /* TODO: TBD maybe check the offset against the size of flash */
> +
> +             E1000_WRITE_ICH_FLASH_REG32(hw, ICH_FLASH_FADDR,
> +                 flash_linear_address);
> +
> +             error = em_ich8_flash_cycle(hw, ICH_FLASH_COMMAND_TIMEOUT);
> +             /*
> +              * Check if FCERR is set to 1, if set to 1, clear it and try
> +              * the whole sequence a few more times, else read in (shift
> +              * in) the Flash Data0, the order is least significant byte
> +              * first msb to lsb
> +              */
> +             if (error == E1000_SUCCESS) {
> +                     (*data) = (uint32_t)E1000_READ_ICH_FLASH_REG32(hw,
> +                         ICH_FLASH_FDATA0);
> +                     break;
> +             } else {
> +                     /*
> +                      * If we've gotten here, then things are probably
> +                      * completely hosed, but if the error condition is
> +                      * detected, it won't hurt to give it another
> +                      * try...ICH_FLASH_CYCLE_REPEAT_COUNT times.
> +                      */
> +                     hsfsts.regval = E1000_READ_ICH_FLASH_REG16(hw,
> +                         ICH_FLASH_HSFSTS);
> +                     if (hsfsts.hsf_status.flcerr == 1) {
> +                             /* Repeat for some time before giving up. */
> +                             continue;
> +                     } else if (hsfsts.hsf_status.flcdone == 0) {
> +                             DEBUGOUT("Timeout error - flash cycle did not"
> +                                 " complete.");
> +                             break;
> +                     }
> +             }
> +     } while (count++ < ICH_FLASH_CYCLE_REPEAT_COUNT);
> +
> +     return error;
> +}
> +
> +
>  
> /******************************************************************************
>   * Writes One /two bytes to the NVM using the ICH8 flash access registers.
>   *
>   * hw - The pointer to the hw structure
> - * index - The index of the byte/word to read.
> + * index - The index of the byte/word to write.
>   * size - Size of data to read, 1=byte 2=word
>   * data - The byte(s) to write to the NVM.
>   
> *****************************************************************************/
> @@ -9768,6 +10056,8 @@ em_write_ich8_data(struct em_hw *hw, uin
>       int32_t  count = 0;
>       DEBUGFUNC("em_write_ich8_data");
>  
> +     if (hw->mac_type == em_pch_spt)
> +             return -E1000_ERR_EEPROM;
>       if (size < 1 || size > 2 || data > size * 0xff ||
>           index > ICH_FLASH_LINEAR_ADDR_MASK)
>               return error;
> @@ -9793,7 +10083,7 @@ em_write_ich8_data(struct em_hw *hw, uin
>                * Write the last 24 bits of index into Flash Linear address
>                * field in Flash Address
>                */
> -             E1000_WRITE_ICH_FLASH_REG(hw, ICH_FLASH_FADDR,
> +             E1000_WRITE_ICH_FLASH_REG32(hw, ICH_FLASH_FADDR,
>                   flash_linear_address);
>  
>               if (size == 1)
> @@ -9801,7 +10091,7 @@ em_write_ich8_data(struct em_hw *hw, uin
>               else
>                       flash_data = (uint32_t) data;
>  
> -             E1000_WRITE_ICH_FLASH_REG(hw, ICH_FLASH_FDATA0, flash_data);
> +             E1000_WRITE_ICH_FLASH_REG32(hw, ICH_FLASH_FDATA0, flash_data);
>               /*
>                * check if FCERR is set to 1 , if set to 1, clear it and try
>                * the whole sequence a few more times else done
> @@ -9833,6 +10123,82 @@ em_write_ich8_data(struct em_hw *hw, uin
>  }

This function is only called by em_verify_write_ich8_dword() which
itself isn't called.  Any reason to keep either of them?

>  
>  
> /******************************************************************************
> + * Writes four bytes to the NVM using the ICH8 flash access registers.
> + *
> + * hw - The pointer to the hw structure
> + * index - The index of the dword to write.
> + * data - The byte(s) to write to the NVM.
> + 
> *****************************************************************************/
> +STATIC int32_t
> +em_write_ich8_data32(struct em_hw *hw, uint32_t index, uint32_t data)
> +{
> +     union ich8_hws_flash_status hsfsts;
> +     union ich8_hws_flash_ctrl hsflctl;
> +     uint32_t flash_linear_address;
> +     int32_t  error = -E1000_ERR_EEPROM;
> +     int32_t  count = 0;
> +     DEBUGFUNC("em_write_ich8_data");
> +
> +     if (hw->mac_type != em_pch_spt)
> +             return error;
> +     if (index > ICH_FLASH_LINEAR_ADDR_MASK)
> +             return error;
> +     flash_linear_address = (ICH_FLASH_LINEAR_ADDR_MASK & index) +
> +         hw->flash_base_addr;
> +
> +     do {
> +             usec_delay(1);
> +             /* Steps */
> +             error = em_ich8_cycle_init(hw);
> +             if (error)
> +                     break;
> +
> +             hsflctl.regval = E1000_READ_ICH_FLASH_REG32(hw,
> +                 ICH_FLASH_HSFSTS) >> 16;
> +             hsflctl.hsf_ctrl.fldbcount = sizeof(uint32_t) - 1;
> +             hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_WRITE;
> +             E1000_WRITE_ICH_FLASH_REG32(hw, ICH_FLASH_HSFCTL,
> +                 (uint32_t)hsflctl.regval << 16);
> +             /*
> +              * Write the last 24 bits of index into Flash Linear address
> +              * field in Flash Address
> +              */
> +             E1000_WRITE_ICH_FLASH_REG32(hw, ICH_FLASH_FADDR,
> +                 flash_linear_address);
> +
> +             E1000_WRITE_ICH_FLASH_REG32(hw, ICH_FLASH_FDATA0, data);
> +
> +             /*
> +              * check if FCERR is set to 1 , if set to 1, clear it and try
> +              * the whole sequence a few more times else done
> +              */
> +             error = em_ich8_flash_cycle(hw,
> +                 ICH_FLASH_COMMAND_TIMEOUT);
> +             if (error == E1000_SUCCESS)
> +                     break;
> +
> +             /*
> +              * If we're here, then things are most likely
> +              * completely hosed, but if the error condition is
> +              * detected, it won't hurt to give it another
> +              * try...ICH_FLASH_CYCLE_REPEAT_COUNT times.
> +              */
> +             hsfsts.regval = E1000_READ_ICH_FLASH_REG32(hw,
> +                 ICH_FLASH_HSFSTS) & 0xffffUL;
> +             if (hsfsts.hsf_status.flcerr == 1)
> +                     /* Repeat for some time before giving up. */
> +                     continue;
> +             if (hsfsts.hsf_status.flcdone == 0) {
> +                     DEBUGOUT("Timeout error - flash cycle did not"
> +                         " complete.");
> +                     break;
> +             }
> +     } while (count++ < ICH_FLASH_CYCLE_REPEAT_COUNT);
> +
> +     return error;
> +}
> +
> +/******************************************************************************
>   * Reads a single byte from the NVM using the ICH8 flash access registers.
>   *
>   * hw - pointer to em_hw structure
> @@ -9844,7 +10210,11 @@ em_read_ich8_byte(struct em_hw *hw, uint
>  {
>       int32_t  status = E1000_SUCCESS;
>       uint16_t word = 0;
> -     status = em_read_ich8_data(hw, index, 1, &word);
> +
> +     if (hw->mac_type == em_pch_spt)
> +             return -E1000_ERR_EEPROM;
> +     else
> +             status = em_read_ich8_data(hw, index, 1, &word);
>       if (status == E1000_SUCCESS) {
>               *data = (uint8_t) word;
>       }
> @@ -9887,6 +10257,39 @@ em_verify_write_ich8_byte(struct em_hw *
>  }
>  
>  
> /******************************************************************************
> + * Writes a single dword to the NVM using the ICH8 flash access registers.
> + * Performs verification by reading back the value and then going through
> + * a retry algorithm before giving up.
> + *
> + * hw - pointer to em_hw structure
> + * index - The byte index of the dword to write.
> + * byte - The byte to write to the NVM.
> + 
> *****************************************************************************/
> +STATIC int32_t
> +em_verify_write_ich8_dword(struct em_hw *hw, uint32_t index, uint32_t dword)
> +{
> +     int32_t error = E1000_SUCCESS;
> +     int32_t program_retries = 0;
> +     DEBUGOUT2("Dword := %8.8X Offset := %d\n", dword, index);
> +
> +     error = em_write_ich8_data32(hw, index, dword);
> +
> +     if (E1000_SUCCESS)
> +             return error;
> +     for (program_retries = 0; program_retries < 100; program_retries++) {
> +             DEBUGOUT2("Retrying \t Byte := %8.8X Offset := %d\n",
> +                 dword, index);
> +             error = em_write_ich8_data32(hw, index, dword);
> +             if (error == E1000_SUCCESS)
> +                     break;
> +     }
> +     if (program_retries == 100)
> +             error = E1000_ERR_EEPROM;
> +
> +     return error;
> +}
> +
> +/******************************************************************************
>   * Writes a single byte to the NVM using the ICH8 flash access registers.
>   *
>   * hw - pointer to em_hw structure
> @@ -9904,6 +10307,21 @@ em_write_ich8_byte(struct em_hw *hw, uin
>  }

In the Intel code in FreeBSD  e1000_read_flash_dword_ich8lan does the
offset shift instead of the caller and checks if data is NULL.

That would make this function seem less pointless.

>  
>  
> /******************************************************************************
> + * Reads a dword from the NVM using the ICH8 flash access registers.
> + *
> + * hw - pointer to em_hw structure
> + * index - The starting BYTE index of the word to read.
> + * data - Pointer to a word to store the value read.
> + 
> *****************************************************************************/
> +STATIC int32_t
> +em_read_ich8_dword(struct em_hw *hw, uint32_t index, uint32_t *data)
> +{
> +     int32_t status = E1000_SUCCESS;
> +     status = em_read_ich8_data32(hw, index, data);
> +     return status;
> +}
> +
> +/******************************************************************************
>   * Reads a word from the NVM using the ICH8 flash access registers.
>   *
>   * hw - pointer to em_hw structure
> @@ -10030,7 +10448,7 @@ em_erase_ich8_4k_segment(struct em_hw *h
>                       flash_linear_address += hw->flash_base_addr;
>                       flash_linear_address &= ICH_FLASH_LINEAR_ADDR_MASK;
>  
> -                     E1000_WRITE_ICH_FLASH_REG(hw, ICH_FLASH_FADDR,
> +                     E1000_WRITE_ICH_FLASH_REG32(hw, ICH_FLASH_FADDR,
>                           flash_linear_address);
>  
>                       error =
> @@ -10230,7 +10648,8 @@ em_init_lcd_from_nvm(struct em_hw *hw)
>           hw->device_id == E1000_DEV_ID_ICH8_IGP_M ||
>           hw->mac_type == em_pchlan ||
>           hw->mac_type == em_pch2lan ||
> -         hw->mac_type == em_pch_lpt)
> +         hw->mac_type == em_pch_lpt ||
> +         hw->mac_type == em_pch_spt)
>               sw_cfg_mask = FEXTNVM_SW_CONFIG_ICH8M;
>       else
>               sw_cfg_mask = FEXTNVM_SW_CONFIG;
> Index: dev/pci/if_em_hw.h
> ===================================================================
> RCS file: /data/mirror/openbsd/cvs/src/sys/dev/pci/if_em_hw.h,v
> retrieving revision 1.67
> diff -u -p -r1.67 if_em_hw.h
> --- dev/pci/if_em_hw.h        12 Sep 2015 02:38:14 -0000      1.67
> +++ dev/pci/if_em_hw.h        4 Feb 2016 14:39:02 -0000
> @@ -80,12 +80,13 @@ typedef enum {
>      em_pchlan,
>      em_pch2lan,
>      em_pch_lpt,
> +    em_pch_spt,
>      em_num_macs
>  } em_mac_type;
>  
>  #define IS_ICH8(t) \
>       (t == em_ich8lan || t == em_ich9lan || t == em_ich10lan || \
> -      t == em_pchlan || t == em_pch2lan || t == em_pch_lpt)
> +      t == em_pchlan || t == em_pch2lan || t == em_pch_lpt || t == 
> em_pch_spt)
>  
>  typedef enum {
>      em_eeprom_uninitialized = 0,
> @@ -554,6 +555,10 @@ int32_t em_check_phy_reset_block(struct 
>  #define E1000_DEV_ID_PCH_I218_V2         0x15A1
>  #define E1000_DEV_ID_PCH_I218_LM3        0x15A2
>  #define E1000_DEV_ID_PCH_I218_V3         0x15A3
> +#define E1000_DEV_ID_PCH_SPT_I219_LM     0x156F
> +#define E1000_DEV_ID_PCH_SPT_I219_V      0x1570
> +#define E1000_DEV_ID_PCH_SPT_I219_LM2    0x15B7
> +#define E1000_DEV_ID_PCH_SPT_I219_V2     0x15B8
>  #define E1000_DEV_ID_82575EB_PT          0x10A7
>  #define E1000_DEV_ID_82575EB_PF          0x10A9
>  #define E1000_DEV_ID_82575GB_QP          0x10D6
> @@ -1030,6 +1035,7 @@ struct em_ffvt_entry {
>  #define FEXTNVM_SW_CONFIG_ICH8M (1 << 27) /* Bit redefined for ICH8M :/ */
>  #define E1000_PBA      0x01000  /* Packet Buffer Allocation - RW */
>  #define E1000_PBS      0x01008  /* Packet Buffer Size */
> +#define E1000_IOSFPC   0x00F28  /* TX corrupted data  */
>  #define E1000_EEMNGCTL 0x01010  /* MNG EEprom Control */
>  #define E1000_FLASH_UPDATES 1000
>  #define E1000_EEARBC   0x01024  /* EEPROM Auto Read Bus Control */
> @@ -2044,6 +2050,7 @@ struct em_hw {
>  #define E1000_RCTL_RDMTS_HALF     0x00000000    /* rx desc min threshold 
> size */
>  #define E1000_RCTL_RDMTS_QUAT     0x00000100    /* rx desc min threshold 
> size */
>  #define E1000_RCTL_RDMTS_EIGTH    0x00000200    /* rx desc min threshold 
> size */
> +#define E1000_RCTL_RDMTS_HEX      0x00010000
>  #define E1000_RCTL_MO_SHIFT       12            /* multicast offset shift */
>  #define E1000_RCTL_MO_0           0x00000000    /* multicast offset 11:0 */
>  #define E1000_RCTL_MO_1           0x00001000    /* multicast offset 12:1 */
> @@ -2145,7 +2152,7 @@ struct em_hw {
>  #define E1000_RXDCTL_PTHRESH 0x0000003F /* RXDCTL Prefetch Threshold */
>  #define E1000_RXDCTL_HTHRESH 0x00003F00 /* RXDCTL Host Threshold */
>  #define E1000_RXDCTL_WTHRESH 0x003F0000 /* RXDCTL Writeback Threshold */
> -#define E1000_RXDCTL_GRAN    0x01000000 /* RXDCTL Granularity */
> +#define E1000_RXDCTL_THRESH_UNIT_DESC 0x1000000
>  #define E1000_RXDCTL_QUEUE_ENABLE 0x2000000
>  
>  /* Transmit Descriptor Control */
> @@ -3728,6 +3735,15 @@ union ich8_hws_flash_regacc {
>  #define I2_SMBUS_CTRL                PHY_REG(769, 23)
>  #define I2_MODE_CTRL         HV_KMRN_MODE_CTRL
>  #define I2_PCIE_POWER_CTRL   IGP3_KMRN_POWER_MNG_CTRL
> +
> +/* FEXTNVM registers */
> +#define E1000_FEXTNVM7                          0xe4UL
> +#define E1000_FEXTNVM7_SIDE_CLK_UNGATE          0x04UL
> +#define E1000_FEXTNVM9                          0x5bb4UL
> +#define E1000_FEXTNVM9_IOSFSB_CLKGATE_DIS       0x0800UL
> +#define E1000_FEXTNVM9_IOSFSB_CLKREQ_DIS        0x1000UL
> +#define E1000_FEXTNVM11                         0x05bbc
> +#define E1000_FEXTNVM11_DISABLE_MULR_FIX        0x00002000
>  
>  /* BM/HV Specific Registers */
>  #define BM_PORT_CTRL_PAGE                 769
> Index: dev/pci/if_em_osdep.h
> ===================================================================
> RCS file: /data/mirror/openbsd/cvs/src/sys/dev/pci/if_em_osdep.h,v
> retrieving revision 1.12
> diff -u -p -r1.12 if_em_osdep.h
> --- dev/pci/if_em_osdep.h     5 Oct 2011 02:52:10 -0000       1.12
> +++ dev/pci/if_em_osdep.h     4 Feb 2016 14:39:02 -0000
> @@ -78,6 +78,7 @@ struct em_osdep
>       bus_addr_t              em_iobase;
>       bus_size_t              em_flashsize;
>       bus_addr_t              em_flashbase;
> +     size_t                  em_flashoffset;
>  };
>  
>  #define E1000_WRITE_FLUSH(hw)        E1000_READ_REG(hw, STATUS)
> @@ -151,21 +152,31 @@ struct em_osdep
>  
>  #define E1000_READ_ICH_FLASH_REG(hw, reg) \
>       bus_space_read_4(((struct em_osdep *)(hw)->back)->flash_bus_space_tag, \
> -                      ((struct em_osdep 
> *)(hw)->back)->flash_bus_space_handle, reg)
> +                      ((struct em_osdep 
> *)(hw)->back)->flash_bus_space_handle, ((struct em_osdep 
> *)(hw)->back)->em_flashoffset + reg)
>  
>  #define E1000_READ_ICH_FLASH_REG16(hw, reg) \
>       bus_space_read_2(((struct em_osdep *)(hw)->back)->flash_bus_space_tag, \
> -                      ((struct em_osdep 
> *)(hw)->back)->flash_bus_space_handle, reg)
> +                      ((struct em_osdep 
> *)(hw)->back)->flash_bus_space_handle, ((struct em_osdep 
> *)(hw)->back)->em_flashoffset + reg)
>  
> -#define E1000_WRITE_ICH_FLASH_REG(hw, reg, value) \
> -     bus_space_write_4(((struct em_osdep *)(hw)->back)->flash_bus_space_tag, 
> \
> +#define E1000_READ_ICH_FLASH_REG32(hw, reg) \
> +     bus_space_read_4(((struct em_osdep *)(hw)->back)->flash_bus_space_tag, \
> +                      ((struct em_osdep 
> *)(hw)->back)->flash_bus_space_handle, ((struct em_osdep 
> *)(hw)->back)->em_flashoffset + reg)
> +
> +
> +#define E1000_WRITE_ICH_FLASH_REG8(hw, reg, value) \
> +     bus_space_write_1(((struct em_osdep *)(hw)->back)->flash_bus_space_tag, 
> \
>                         ((struct em_osdep 
> *)(hw)->back)->flash_bus_space_handle, \
> -                        reg, value)
> +                        ((struct em_osdep *)(hw)->back)->em_flashoffset + 
> reg, value)
>  
>  #define E1000_WRITE_ICH_FLASH_REG16(hw, reg, value) \
>       bus_space_write_2(((struct em_osdep *)(hw)->back)->flash_bus_space_tag, 
> \
>                         ((struct em_osdep 
> *)(hw)->back)->flash_bus_space_handle, \
> -                        reg, value)
> +                        ((struct em_osdep *)(hw)->back)->em_flashoffset + 
> reg, value)
> +
> +#define E1000_WRITE_ICH_FLASH_REG32(hw, reg, value) \
> +     bus_space_write_4(((struct em_osdep *)(hw)->back)->flash_bus_space_tag, 
> \
> +                       ((struct em_osdep 
> *)(hw)->back)->flash_bus_space_handle, \
> +                        ((struct em_osdep *)(hw)->back)->em_flashoffset + 
> reg, value)
>  
>  #define em_io_read(hw, port) \
>       bus_space_read_4(((struct em_osdep *)(hw)->back)->io_bus_space_tag, \
> Index: dev/pci/pcidevs
> ===================================================================
> RCS file: /data/mirror/openbsd/cvs/src/sys/dev/pci/pcidevs,v
> retrieving revision 1.1786
> diff -u -p -r1.1786 pcidevs
> --- dev/pci/pcidevs   30 Jan 2016 01:02:04 -0000      1.1786
> +++ dev/pci/pcidevs   4 Feb 2016 16:04:31 -0000
> @@ -3353,6 +3353,10 @@ product INTEL I218_LM_2                0x15a0  I218-LM
>  product INTEL I218_V_2               0x15a1  I218-V
>  product INTEL I218_LM_3              0x15a2  I218-LM
>  product INTEL I218_V_3               0x15a3  I218-V
> +product INTEL I219_LM                0x156F  I219_LM
> +product INTEL I219_V         0x1570  I219_V
> +product INTEL I219_LM2               0x15B7  I219_LM2
> +product INTEL I219_V2                0x15B8  I219_V2

In addition to the ordering already mentioned use lowercase for hex digits
in pcidevs.

>  product INTEL X557_AT2               0x15ad  X557-AT2
>  product INTEL CORE5G_H_PCIE_X16      0x1601  Core 5G PCIE
>  product INTEL CORE5G_M_GT1_1 0x1602  HD Graphics
> Index: dev/pci/pcidevs.h
> ===================================================================
> RCS file: /data/mirror/openbsd/cvs/src/sys/dev/pci/pcidevs.h,v
> retrieving revision 1.1779
> diff -u -p -r1.1779 pcidevs.h
> --- dev/pci/pcidevs.h 30 Jan 2016 01:02:39 -0000      1.1779
> +++ dev/pci/pcidevs.h 4 Feb 2016 16:04:42 -0000
> @@ -3358,6 +3358,10 @@
>  #define      PCI_PRODUCT_INTEL_I218_V_2      0x15a1          /* I218-V */
>  #define      PCI_PRODUCT_INTEL_I218_LM_3     0x15a2          /* I218-LM */
>  #define      PCI_PRODUCT_INTEL_I218_V_3      0x15a3          /* I218-V */
> +#define      PCI_PRODUCT_INTEL_I219_LM       0x156F          /* I219_LM */
> +#define      PCI_PRODUCT_INTEL_I219_V        0x1570          /* I219_V */
> +#define      PCI_PRODUCT_INTEL_I219_LM2      0x15B7          /* I219_LM2 */
> +#define      PCI_PRODUCT_INTEL_I219_V2       0x15B8          /* I219_V2 */
>  #define      PCI_PRODUCT_INTEL_X557_AT2      0x15ad          /* X557-AT2 */
>  #define      PCI_PRODUCT_INTEL_CORE5G_H_PCIE_X16     0x1601          /* Core 
> 5G PCIE */
>  #define      PCI_PRODUCT_INTEL_CORE5G_M_GT1_1        0x1602          /* HD 
> Graphics */
> Index: dev/pci/pcidevs_data.h
> ===================================================================
> RCS file: /data/mirror/openbsd/cvs/src/sys/dev/pci/pcidevs_data.h,v
> retrieving revision 1.1774
> diff -u -p -r1.1774 pcidevs_data.h
> --- dev/pci/pcidevs_data.h    30 Jan 2016 01:02:39 -0000      1.1774
> +++ dev/pci/pcidevs_data.h    4 Feb 2016 16:04:42 -0000
> @@ -10952,6 +10952,22 @@ static const struct pci_known_product pc
>           "I218-V",
>       },
>       {
> +         PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_I219_LM,
> +         "I219_LM",
> +     },
> +     {
> +         PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_I219_V,
> +         "I219_V",
> +     },
> +     {
> +         PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_I219_LM2,
> +         "I219_LM2",
> +     },
> +     {
> +         PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_I219_V2,
> +         "I219_V2",
> +     },
> +     {
>           PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_X557_AT2,
>           "X557-AT2",
>       },


Reply via email to