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",
> },