summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorpdeuskar <pdeuskar@FreeBSD.org>2002-07-16 16:55:03 +0000
committerpdeuskar <pdeuskar@FreeBSD.org>2002-07-16 16:55:03 +0000
commit7995d306bcdcaa2681090cfcaed794f15a85c77d (patch)
tree284e4f4e8951c0bd2650ac202095af1ba0c16b3f
parent4410d83dcc36f0f5f77a472d9371eb764d2e3d62 (diff)
downloadFreeBSD-src-7995d306bcdcaa2681090cfcaed794f15a85c77d.zip
FreeBSD-src-7995d306bcdcaa2681090cfcaed794f15a85c77d.tar.gz
- Use IO mode to reset the controller (82544 and beyond)
- Read the Mac address only once during attach. (This fixes the failover issue observed using the bonding driver) MFC after: 3 days
-rw-r--r--sys/dev/em/README28
-rw-r--r--sys/dev/em/if_em.c127
-rw-r--r--sys/dev/em/if_em.h4
-rw-r--r--sys/dev/em/if_em_hw.c301
-rw-r--r--sys/dev/em/if_em_hw.h34
-rw-r--r--sys/dev/em/if_em_osdep.h38
6 files changed, 429 insertions, 103 deletions
diff --git a/sys/dev/em/README b/sys/dev/em/README
index cb3c8b9..4603056 100644
--- a/sys/dev/em/README
+++ b/sys/dev/em/README
@@ -1,9 +1,8 @@
$FreeBSD$
-
FreeBSD* Driver for the Intel(R) PRO/1000 Family of Adapters
============================================================
-April 3, 2002
+July 2, 2002
Contents
@@ -24,14 +23,13 @@ In This Release
This file describes the FreeBSD* driver, version 1.3.x, for the Intel(R)
PRO/1000 Family of Adapters. This driver has been developed for use with
-FreeBSD, version 4.5.
+FreeBSD, version 4.6. As a new feature for this release, the driver is now
+compiled by default into the FreeBSD 4.6 kernel.
The driver supports Transmit/Receive Checksum Offload and Jumbo Frames on
all but the 82542-based adapters. For specific adapters, refer to the
Supported Adapters section below.
-Support for VLANs has been added as a new feature in this driver version.
-
For questions related to hardware requirements, refer to the documentation
supplied with your Intel PRO/1000 adapter. All hardware requirements listed
apply to use with FreeBSD.
@@ -146,31 +144,19 @@ NOTE: You must have kernel sources installed in order to compile the driver
7. If you want to compile the driver into the kernel, enter:
- mkdir /usr/src/sys/dev/em
cd em-x.x.x/src
cp if_em* /usr/src/sys/dev/em
- mkdir /usr/src/sys/modules/em
cp Makefile /usr/src/sys/modules/em
- Edit Makefile at /usr/src/sys/modules to add the em subdirectory.
-
- Edit your config file and add the following line, if it is not already
- in the file:
-
- device em
-
- Edit your config file, and remove the 'device wx' line from the file.
-
- Edit the /usr/src/sys/conf/files.i386 file, and add the following lines:
+ Edit the /usr/src/sys/conf/files.i386 file, and add the following line:
- dev/em/if_em.c optional em
dev/em/if_em_hw.c optional em
- Remove the following files from the /usr/src/sys/conf/files.i386 file, if
+ Remove the following lines from the /usr/src/sys/conf/files.i386 file, if
they exist:
- /dev/em/if_em_fxhw.c
- /dev/em/if_em_phy.c
+ /dev/em/if_em_fxhw.c optional em
+ /dev/em/if_em_phy.c optional em
Compile and install the kernel.
diff --git a/sys/dev/em/if_em.c b/sys/dev/em/if_em.c
index e91abd6..f28143a 100644
--- a/sys/dev/em/if_em.c
+++ b/sys/dev/em/if_em.c
@@ -53,7 +53,7 @@ struct adapter *em_adapter_list = NULL;
* Driver version
*********************************************************************/
-char em_driver_version[] = "1.3.8";
+char em_driver_version[] = "1.3.14";
/*********************************************************************
@@ -128,20 +128,20 @@ static int em_allocate_receive_structures(struct adapter *);
static int em_allocate_transmit_structures(struct adapter *);
static void em_process_receive_interrupts(struct adapter *);
static void em_receive_checksum(struct adapter *,
- struct em_rx_desc * rx_desc,
- struct mbuf *);
+ struct em_rx_desc * rx_desc,
+ struct mbuf *);
static void em_transmit_checksum_setup(struct adapter *,
- struct mbuf *,
- struct em_tx_buffer *,
- u_int32_t *,
- u_int32_t *);
+ struct mbuf *,
+ struct em_tx_buffer *,
+ u_int32_t *,
+ u_int32_t *);
static void em_set_promisc(struct adapter *);
static void em_disable_promisc(struct adapter *);
static void em_set_multi(struct adapter *);
static void em_print_hw_stats(struct adapter *);
static void em_print_link_status(struct adapter *);
static int em_get_buf(struct em_rx_buffer *, struct adapter *,
- struct mbuf *);
+ struct mbuf *);
static void em_enable_vlans(struct adapter *adapter);
/*********************************************************************
@@ -267,7 +267,6 @@ em_attach(device_t dev)
adapter->hw.autoneg_advertised = AUTONEG_ADV_DEFAULT;
adapter->hw.tbi_compatibility_en = TRUE;
adapter->rx_buffer_len = EM_RXBUFFER_2048;
- adapter->rx_checksum = EM_ENABLE_RXCSUM_OFFLOAD;
adapter->hw.fc_high_water = FC_DEFAULT_HI_THRESH;
adapter->hw.fc_low_water = FC_DEFAULT_LO_THRESH;
@@ -339,6 +338,16 @@ em_attach(device_t dev)
return(EIO);
}
+ /* Copy the permanent MAC address out of the EEPROM */
+ if (em_read_mac_addr(&adapter->hw) < 0) {
+ printf("em%d: EEPROM read error while reading mac address\n",
+ adapter->unit);
+ return(EIO);
+ }
+
+ memcpy(adapter->interface_data.ac_enaddr, adapter->hw.mac_addr,
+ ETH_LENGTH_OF_ADDRESS);
+
/* Setup OS specific network interface */
em_setup_interface(dev, adapter);
@@ -1051,7 +1060,11 @@ em_media_status(struct ifnet *ifp, struct ifmediareq *ifmr)
ifmr->ifm_active |= IFM_100_TX;
break;
case 1000:
+#if __FreeBSD_version < 500000
+ ifmr->ifm_active |= IFM_1000_TX;
+#else
ifmr->ifm_active |= IFM_1000_T;
+#endif
break;
}
if (adapter->link_duplex == FULL_DUPLEX)
@@ -1087,7 +1100,11 @@ em_media_change(struct ifnet *ifp)
adapter->hw.autoneg_advertised = AUTONEG_ADV_DEFAULT;
break;
case IFM_1000_SX:
+#if __FreeBSD_version < 500000
+ case IFM_1000_TX:
+#else
case IFM_1000_T:
+#endif
adapter->hw.autoneg = DO_AUTO_NEG;
adapter->hw.autoneg_advertised = ADVERTISE_1000_FULL;
break;
@@ -1183,26 +1200,53 @@ em_identify_hardware(struct adapter * adapter)
static int
em_allocate_pci_resources(struct adapter * adapter)
{
- int resource_id = EM_MMBA;
+ int i, val, rid;
device_t dev = adapter->dev;
+ rid = EM_MMBA;
adapter->res_memory = bus_alloc_resource(dev, SYS_RES_MEMORY,
- &resource_id, 0, ~0, 1,
+ &rid, 0, ~0, 1,
RF_ACTIVE);
if (!(adapter->res_memory)) {
printf("em%d: Unable to allocate bus resource: memory\n",
adapter->unit);
return(ENXIO);
}
- adapter->osdep.bus_space_tag =
+ adapter->osdep.mem_bus_space_tag =
rman_get_bustag(adapter->res_memory);
- adapter->osdep.bus_space_handle =
+ adapter->osdep.mem_bus_space_handle =
rman_get_bushandle(adapter->res_memory);
- adapter->hw.hw_addr = (uint8_t *)&adapter->osdep.bus_space_handle;
+ adapter->hw.hw_addr = (uint8_t *)&adapter->osdep.mem_bus_space_handle;
+
- resource_id = 0x0;
+ if (adapter->hw.mac_type > em_82543) {
+ /* Figure our where our IO BAR is ? */
+ rid = EM_MMBA;
+ for (i = 0; i < 5; i++) {
+ val = pci_read_config(dev, rid, 4);
+ if (val & 0x00000001) {
+ adapter->io_rid = rid;
+ break;
+ }
+ rid += 4;
+ }
+
+ adapter->res_ioport = bus_alloc_resource(dev, SYS_RES_IOPORT,
+ &adapter->io_rid, 0, ~0, 1,
+ RF_ACTIVE);
+ if (!(adapter->res_ioport)) {
+ printf("em%d: Unable to allocate bus resource: ioport\n",
+ adapter->unit);
+ return(ENXIO);
+ }
+
+ adapter->hw.io_base =
+ rman_get_start(adapter->res_ioport);
+ }
+
+ rid = 0x0;
adapter->res_interrupt = bus_alloc_resource(dev, SYS_RES_IRQ,
- &resource_id, 0, ~0, 1,
+ &rid, 0, ~0, 1,
RF_SHAREABLE | RF_ACTIVE);
if (!(adapter->res_interrupt)) {
printf("em%d: Unable to allocate bus resource: interrupt\n",
@@ -1237,6 +1281,11 @@ em_free_pci_resources(struct adapter * adapter)
bus_release_resource(dev, SYS_RES_MEMORY, EM_MMBA,
adapter->res_memory);
}
+
+ if (adapter->res_ioport != NULL) {
+ bus_release_resource(dev, SYS_RES_IOPORT, adapter->io_rid,
+ adapter->res_ioport);
+ }
return;
}
@@ -1260,16 +1309,6 @@ em_hardware_init(struct adapter * adapter)
adapter->unit);
return(EIO);
}
- /* Copy the permanent MAC address and part number out of the EEPROM */
- if (em_read_mac_addr(&adapter->hw) < 0) {
- printf("em%d: EEPROM read error while reading mac address\n",
- adapter->unit);
- return(EIO);
- }
-
- memcpy(adapter->interface_data.ac_enaddr, adapter->hw.mac_addr,
- ETH_LENGTH_OF_ADDRESS);
-
if (em_read_part_num(&adapter->hw, &(adapter->part_num)) < 0) {
printf("em%d: EEPROM read error while reading part number\n",
@@ -1351,9 +1390,15 @@ em_setup_interface(device_t dev, struct adapter * adapter)
0, NULL);
ifmedia_add(&adapter->media, IFM_ETHER | IFM_100_TX | IFM_FDX,
0, NULL);
+#if __FreeBSD_version < 500000
+ ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_TX | IFM_FDX,
+ 0, NULL);
+ ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_TX, 0, NULL);
+#else
ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_T | IFM_FDX,
0, NULL);
ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_T, 0, NULL);
+#endif
}
ifmedia_add(&adapter->media, IFM_ETHER | IFM_AUTO, 0, NULL);
ifmedia_set(&adapter->media, IFM_ETHER | IFM_AUTO);
@@ -1799,8 +1844,9 @@ em_initialize_receive_unit(struct adapter * adapter)
switch (adapter->rx_buffer_len) {
+ default:
case EM_RXBUFFER_2048:
- reg_rctl |= E1000_RCTL_SZ_2048 | E1000_RCTL_LPE;
+ reg_rctl |= E1000_RCTL_SZ_2048;
break;
case EM_RXBUFFER_4096:
reg_rctl |= E1000_RCTL_SZ_4096 | E1000_RCTL_BSEX | E1000_RCTL_LPE;
@@ -1811,10 +1857,11 @@ em_initialize_receive_unit(struct adapter * adapter)
case EM_RXBUFFER_16384:
reg_rctl |= E1000_RCTL_SZ_16384 | E1000_RCTL_BSEX | E1000_RCTL_LPE;
break;
- default:
- reg_rctl |= E1000_RCTL_SZ_2048;
}
+ if (ifp->if_mtu > ETHERMTU)
+ reg_rctl |= E1000_RCTL_LPE;
+
/* Enable 82543 Receive Checksum Offload for TCP and UDP */
if ((adapter->hw.mac_type >= em_82543) &&
(ifp->if_capenable & IFCAP_RXCSUM)) {
@@ -2091,14 +2138,32 @@ em_disable_intr(struct adapter *adapter)
return;
}
-void em_write_pci_cfg(struct em_hw *adapter,
+void em_write_pci_cfg(struct em_hw *hw,
uint32_t reg,
uint16_t *value)
{
- pci_write_config(((struct em_osdep *)adapter->back)->dev, reg,
+ pci_write_config(((struct em_osdep *)hw->back)->dev, reg,
*value, 2);
}
+void em_read_pci_cfg(struct em_hw *hw, uint32_t reg,
+ uint16_t *value)
+{
+ *value = pci_read_config(((struct em_osdep *)hw->back)->dev,
+ reg, 2);
+ return;
+}
+
+uint32_t em_io_read(struct em_hw *hw, uint32_t port)
+{
+ return(inl(port));
+}
+
+void em_io_write(struct em_hw *hw, uint32_t port, uint32_t value)
+{
+ outl(port, value);
+ return;
+}
/**********************************************************************
*
diff --git a/sys/dev/em/if_em.h b/sys/dev/em/if_em.h
index 3dc8b44..d548437 100644
--- a/sys/dev/em/if_em.h
+++ b/sys/dev/em/if_em.h
@@ -88,7 +88,6 @@ SUCH DAMAGE.
#define AUTONEG_ADV_DEFAULT (ADVERTISE_10_HALF | ADVERTISE_10_FULL | \
ADVERTISE_100_HALF | ADVERTISE_100_FULL | \
ADVERTISE_1000_FULL)
-#define EM_ENABLE_RXCSUM_OFFLOAD 1
#define EM_REPORT_TX_EARLY 2
#define EM_CHECKSUM_FEATURES (CSUM_TCP | CSUM_UDP)
#define EM_MAX_INTR 3
@@ -185,10 +184,12 @@ struct adapter {
struct em_osdep osdep;
struct device *dev;
struct resource *res_memory;
+ struct resource *res_ioport;
struct resource *res_interrupt;
void *int_handler_tag;
struct ifmedia media;
struct callout_handle timer_handle;
+ int io_rid;
u_int8_t unit;
/* Info about the board itself */
@@ -199,7 +200,6 @@ struct adapter {
u_int32_t tx_int_delay;
u_int32_t rx_int_delay;
- u_int8_t rx_checksum;
XSUM_CONTEXT_T active_checksum_context;
/* Transmit definitions */
diff --git a/sys/dev/em/if_em_hw.c b/sys/dev/em/if_em_hw.c
index 17135f1..c000bb4 100644
--- a/sys/dev/em/if_em_hw.c
+++ b/sys/dev/em/if_em_hw.c
@@ -109,7 +109,11 @@ em_reset_hw(struct em_hw *hw)
*/
DEBUGOUT("Issuing a global reset to MAC\n");
ctrl = E1000_READ_REG(hw, CTRL);
- E1000_WRITE_REG(hw, CTRL, (ctrl | E1000_CTRL_RST));
+
+ if(hw->mac_type > em_82543)
+ E1000_WRITE_REG_IO(hw, CTRL, (ctrl | E1000_CTRL_RST));
+ else
+ E1000_WRITE_REG(hw, CTRL, (ctrl | E1000_CTRL_RST));
/* Force a reload from the EEPROM if necessary */
if(hw->mac_type < em_82540) {
@@ -161,14 +165,18 @@ em_init_hw(struct em_hw *hw)
uint32_t i;
int32_t ret_val;
uint16_t pci_cmd_word;
+ uint16_t pcix_cmd_word;
+ uint16_t pcix_stat_hi_word;
+ uint16_t cmd_mmrbc;
+ uint16_t stat_mmrbc;
DEBUGFUNC("em_init_hw");
/* Initialize Identification LED */
ret_val = em_id_led_init(hw);
if(ret_val < 0) {
- DEBUGOUT("Error Initializing Identification LED\n");
- return ret_val;
+ DEBUGOUT("Error Initializing Identification LED\n");
+ return ret_val;
}
/* Set the Media Type and exit with error if it is not valid. */
@@ -235,6 +243,21 @@ em_init_hw(struct em_hw *hw)
E1000_WRITE_REG(hw, CTRL, ctrl | E1000_CTRL_PRIOR);
}
+ /* Workaround for PCI-X problem when BIOS sets MMRBC incorrectly. */
+ if(hw->bus_type == em_bus_type_pcix) {
+ em_read_pci_cfg(hw, PCIX_COMMAND_REGISTER, &pcix_cmd_word);
+ em_read_pci_cfg(hw, PCIX_STATUS_REGISTER_HI, &pcix_stat_hi_word);
+ cmd_mmrbc = (pcix_cmd_word & PCIX_COMMAND_MMRBC_MASK) >>
+ PCIX_COMMAND_MMRBC_SHIFT;
+ stat_mmrbc = (pcix_stat_hi_word & PCIX_STATUS_HI_MMRBC_MASK) >>
+ PCIX_STATUS_HI_MMRBC_SHIFT;
+ if(cmd_mmrbc > stat_mmrbc) {
+ pcix_cmd_word &= ~PCIX_COMMAND_MMRBC_MASK;
+ pcix_cmd_word |= stat_mmrbc << PCIX_COMMAND_MMRBC_SHIFT;
+ em_write_pci_cfg(hw, PCIX_COMMAND_REGISTER, &pcix_cmd_word);
+ }
+ }
+
/* Call a subroutine to configure the link and setup flow control. */
ret_val = em_setup_link(hw);
@@ -2337,6 +2360,47 @@ em_standby_eeprom(struct em_hw *hw)
usec_delay(50);
}
+/******************************************************************************
+ * Raises then lowers the EEPROM's clock pin
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+static void
+em_clock_eeprom(struct em_hw *hw)
+{
+ uint32_t eecd;
+
+ eecd = E1000_READ_REG(hw, EECD);
+
+ /* Rising edge of clock */
+ eecd |= E1000_EECD_SK;
+ E1000_WRITE_REG(hw, EECD, eecd);
+ usec_delay(50);
+
+ /* Falling edge of clock */
+ eecd &= ~E1000_EECD_SK;
+ E1000_WRITE_REG(hw, EECD, eecd);
+ usec_delay(50);
+}
+
+/******************************************************************************
+ * Terminates a command by lowering the EEPROM's chip select pin
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+static void
+em_cleanup_eeprom(struct em_hw *hw)
+{
+ uint32_t eecd;
+
+ eecd = E1000_READ_REG(hw, EECD);
+
+ eecd &= ~(E1000_EECD_CS | E1000_EECD_DI);
+
+ E1000_WRITE_REG(hw, EECD, eecd);
+
+ em_clock_eeprom(hw);
+}
/******************************************************************************
* Reads a 16 bit word from the EEPROM.
@@ -2439,6 +2503,152 @@ em_validate_eeprom_checksum(struct em_hw *hw)
}
/******************************************************************************
+ * Calculates the EEPROM checksum and writes it to the EEPROM
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Sums the first 63 16 bit words of the EEPROM. Subtracts the sum from 0xBABA.
+ * Writes the difference to word offset 63 of the EEPROM.
+ *****************************************************************************/
+int32_t
+em_update_eeprom_checksum(struct em_hw *hw)
+{
+ uint16_t checksum = 0;
+ uint16_t i, eeprom_data;
+
+ DEBUGFUNC("em_update_eeprom_checksum");
+
+ for(i = 0; i < EEPROM_CHECKSUM_REG; i++) {
+ if(em_read_eeprom(hw, i, &eeprom_data) < 0) {
+ DEBUGOUT("EEPROM Read Error\n");
+ return -E1000_ERR_EEPROM;
+ }
+ checksum += eeprom_data;
+ }
+ checksum = (uint16_t) EEPROM_SUM - checksum;
+ if(em_write_eeprom(hw, EEPROM_CHECKSUM_REG, checksum) < 0) {
+ DEBUGOUT("EEPROM Write Error\n");
+ return -E1000_ERR_EEPROM;
+ }
+ return 0;
+}
+
+/******************************************************************************
+ * Writes a 16 bit word to a given offset in the EEPROM.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * offset - offset within the EEPROM to be written to
+ * data - 16 bit word to be writen to the EEPROM
+ *
+ * If em_update_eeprom_checksum is not called after this function, the
+ * EEPROM will most likely contain an invalid checksum.
+ *****************************************************************************/
+int32_t
+em_write_eeprom(struct em_hw *hw,
+ uint16_t offset,
+ uint16_t data)
+{
+ uint32_t eecd;
+ uint32_t i = 0;
+ int32_t status = 0;
+ boolean_t large_eeprom = FALSE;
+
+ DEBUGFUNC("em_write_eeprom");
+
+ /* Request EEPROM Access */
+ if(hw->mac_type > em_82544) {
+ eecd = E1000_READ_REG(hw, EECD);
+ if(eecd & E1000_EECD_SIZE) large_eeprom = TRUE;
+ eecd |= E1000_EECD_REQ;
+ E1000_WRITE_REG(hw, EECD, eecd);
+ eecd = E1000_READ_REG(hw, EECD);
+ while((!(eecd & E1000_EECD_GNT)) && (i < 100)) {
+ i++;
+ usec_delay(5);
+ eecd = E1000_READ_REG(hw, EECD);
+ }
+ if(!(eecd & E1000_EECD_GNT)) {
+ eecd &= ~E1000_EECD_REQ;
+ E1000_WRITE_REG(hw, EECD, eecd);
+ DEBUGOUT("Could not acquire EEPROM grant\n");
+ return -E1000_ERR_EEPROM;
+ }
+ }
+
+ /* Prepare the EEPROM for writing */
+ em_setup_eeprom(hw);
+
+ /* Send the 9-bit (or 11-bit on large EEPROM) EWEN (write enable) command
+ * to the EEPROM (5-bit opcode plus 4/6-bit dummy). This puts the EEPROM
+ * into write/erase mode.
+ */
+ em_shift_out_ee_bits(hw, EEPROM_EWEN_OPCODE, 5);
+ if(large_eeprom)
+ em_shift_out_ee_bits(hw, 0, 6);
+ else
+ em_shift_out_ee_bits(hw, 0, 4);
+
+ /* Prepare the EEPROM */
+ em_standby_eeprom(hw);
+
+ /* Send the Write command (3-bit opcode + addr) */
+ em_shift_out_ee_bits(hw, EEPROM_WRITE_OPCODE, 3);
+ if(large_eeprom)
+ /* If we have a 256 word EEPROM, there are 8 address bits */
+ em_shift_out_ee_bits(hw, offset, 8);
+ else
+ /* If we have a 64 word EEPROM, there are 6 address bits */
+ em_shift_out_ee_bits(hw, offset, 6);
+
+ /* Send the data */
+ em_shift_out_ee_bits(hw, data, 16);
+
+ /* Toggle the CS line. This in effect tells to EEPROM to actually execute
+ * the command in question.
+ */
+ em_standby_eeprom(hw);
+
+ /* Now read DO repeatedly until is high (equal to '1'). The EEEPROM will
+ * signal that the command has been completed by raising the DO signal.
+ * If DO does not go high in 10 milliseconds, then error out.
+ */
+ for(i = 0; i < 200; i++) {
+ eecd = E1000_READ_REG(hw, EECD);
+ if(eecd & E1000_EECD_DO) break;
+ usec_delay(50);
+ }
+ if(i == 200) {
+ DEBUGOUT("EEPROM Write did not complete\n");
+ status = -E1000_ERR_EEPROM;
+ }
+
+ /* Recover from write */
+ em_standby_eeprom(hw);
+
+ /* Send the 9-bit (or 11-bit on large EEPROM) EWDS (write disable) command
+ * to the EEPROM (5-bit opcode plus 4/6-bit dummy). This takes the EEPROM
+ * out of write/erase mode.
+ */
+ em_shift_out_ee_bits(hw, EEPROM_EWDS_OPCODE, 5);
+ if(large_eeprom)
+ em_shift_out_ee_bits(hw, 0, 6);
+ else
+ em_shift_out_ee_bits(hw, 0, 4);
+
+ /* Done with writing */
+ em_cleanup_eeprom(hw);
+
+ /* Stop requesting EEPROM access */
+ if(hw->mac_type > em_82544) {
+ eecd = E1000_READ_REG(hw, EECD);
+ eecd &= ~E1000_EECD_REQ;
+ E1000_WRITE_REG(hw, EECD, eecd);
+ }
+
+ return status;
+}
+
+/******************************************************************************
* Reads the adapter's part number from the EEPROM
*
* hw - Struct containing variables accessed by shared code
@@ -2775,12 +2985,12 @@ em_id_led_init(struct em_hw * hw)
const uint32_t ledctl_off = E1000_LEDCTL_MODE_LED_OFF;
uint16_t eeprom_data, i, temp;
const uint16_t led_mask = 0x0F;
-
+
DEBUGFUNC("em_id_led_init");
if(hw->mac_type < em_82540) {
- /* Nothing to do */
- return 0;
+ /* Nothing to do */
+ return 0;
}
ledctl = E1000_READ_REG(hw, LEDCTL);
@@ -2797,39 +3007,39 @@ em_id_led_init(struct em_hw * hw)
for(i = 0; i < 4; i++) {
temp = (eeprom_data >> (i << 2)) & led_mask;
switch(temp) {
- case ID_LED_ON1_DEF2:
- case ID_LED_ON1_ON2:
- case ID_LED_ON1_OFF2:
+ case ID_LED_ON1_DEF2:
+ case ID_LED_ON1_ON2:
+ case ID_LED_ON1_OFF2:
hw->ledctl_mode1 &= ~(ledctl_mask << (i << 3));
hw->ledctl_mode1 |= ledctl_on << (i << 3);
break;
- case ID_LED_OFF1_DEF2:
- case ID_LED_OFF1_ON2:
- case ID_LED_OFF1_OFF2:
+ case ID_LED_OFF1_DEF2:
+ case ID_LED_OFF1_ON2:
+ case ID_LED_OFF1_OFF2:
hw->ledctl_mode1 &= ~(ledctl_mask << (i << 3));
hw->ledctl_mode1 |= ledctl_off << (i << 3);
break;
- default:
- /* Do nothing */
- break;
- }
- switch(temp) {
- case ID_LED_DEF1_ON2:
- case ID_LED_ON1_ON2:
- case ID_LED_OFF1_ON2:
+ default:
+ /* Do nothing */
+ break;
+ }
+ switch(temp) {
+ case ID_LED_DEF1_ON2:
+ case ID_LED_ON1_ON2:
+ case ID_LED_OFF1_ON2:
hw->ledctl_mode2 &= ~(ledctl_mask << (i << 3));
hw->ledctl_mode2 |= ledctl_on << (i << 3);
break;
- case ID_LED_DEF1_OFF2:
- case ID_LED_ON1_OFF2:
- case ID_LED_OFF1_OFF2:
+ case ID_LED_DEF1_OFF2:
+ case ID_LED_ON1_OFF2:
+ case ID_LED_OFF1_OFF2:
hw->ledctl_mode2 &= ~(ledctl_mask << (i << 3));
hw->ledctl_mode2 |= ledctl_off << (i << 3);
break;
- default:
- /* Do nothing */
- break;
- }
+ default:
+ /* Do nothing */
+ break;
+ }
}
return 0;
}
@@ -3278,4 +3488,41 @@ em_get_bus_info(struct em_hw *hw)
hw->bus_width = (status & E1000_STATUS_BUS64) ?
em_bus_width_64 : em_bus_width_32;
}
+/******************************************************************************
+ * Reads a value from one of the devices registers using port I/O (as opposed
+ * memory mapped I/O). Only 82544 and newer devices support port I/O.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * offset - offset to read from
+ *****************************************************************************/
+uint32_t
+em_read_reg_io(struct em_hw *hw,
+ uint32_t offset)
+{
+ uint32_t io_addr = hw->io_base;
+ uint32_t io_data = hw->io_base + 4;
+
+ em_io_write(hw, io_addr, offset);
+ return em_io_read(hw, io_data);
+}
+
+/******************************************************************************
+ * Writes a value to one of the devices registers using port I/O (as opposed to
+ * memory mapped I/O). Only 82544 and newer devices support port I/O.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * offset - offset to write to
+ * value - value to write
+ *****************************************************************************/
+void
+em_write_reg_io(struct em_hw *hw,
+ uint32_t offset,
+ uint32_t value)
+{
+ uint32_t io_addr = hw->io_base;
+ uint32_t io_data = hw->io_base + 4;
+
+ em_io_write(hw, io_addr, offset);
+ em_io_write(hw, io_data, value);
+}
diff --git a/sys/dev/em/if_em_hw.h b/sys/dev/em/if_em_hw.h
index 2daca23..f2bf253 100644
--- a/sys/dev/em/if_em_hw.h
+++ b/sys/dev/em/if_em_hw.h
@@ -199,6 +199,8 @@ int32_t em_validate_mdi_setting(struct em_hw *hw);
/* EEPROM Functions */
int32_t em_read_eeprom(struct em_hw *hw, uint16_t reg, uint16_t *data);
int32_t em_validate_eeprom_checksum(struct em_hw *hw);
+int32_t em_update_eeprom_checksum(struct em_hw *hw);
+int32_t em_write_eeprom(struct em_hw *hw, uint16_t reg, uint16_t data);
int32_t em_read_part_num(struct em_hw *hw, uint32_t * part_num);
int32_t em_read_mac_addr(struct em_hw * hw);
@@ -225,7 +227,17 @@ void em_reset_adaptive(struct em_hw *hw);
void em_update_adaptive(struct em_hw *hw);
void em_tbi_adjust_stats(struct em_hw *hw, struct em_hw_stats *stats, uint32_t frame_len, uint8_t * mac_addr);
void em_get_bus_info(struct em_hw *hw);
+void em_read_pci_cfg(struct em_hw *hw, uint32_t reg, uint16_t * value);
void em_write_pci_cfg(struct em_hw *hw, uint32_t reg, uint16_t * value);
+/* Port I/O is only supported on 82544 and newer */
+uint32_t em_io_read(struct em_hw *hw, uint32_t port);
+uint32_t em_read_reg_io(struct em_hw *hw, uint32_t offset);
+void em_io_write(struct em_hw *hw, uint32_t port, uint32_t value);
+void em_write_reg_io(struct em_hw *hw, uint32_t offset, uint32_t value);
+#define E1000_READ_REG_IO(a, reg) \
+ em_read_reg_io((a), E1000_##reg)
+#define E1000_WRITE_REG_IO(a, reg, val) \
+ em_write_reg_io((a), E1000_##reg, val)
/* PCI Device IDs */
#define E1000_DEV_ID_82542 0x1000
@@ -840,6 +852,7 @@ struct em_hw {
em_bus_speed bus_speed;
em_bus_width bus_width;
em_bus_type bus_type;
+ uint32_t io_base;
uint32_t phy_id;
uint32_t phy_addr;
uint32_t original_fc;
@@ -1295,6 +1308,7 @@ struct em_hw {
#define EEPROM_EWDS_OPCODE 0x10 /* EERPOM erast/write disable */
/* EEPROM Word Offsets */
+#define EEPROM_COMPAT 0x0003
#define EEPROM_ID_LED_SETTINGS 0x0004
#define EEPROM_INIT_CONTROL1_REG 0x000A
#define EEPROM_INIT_CONTROL2_REG 0x000F
@@ -1305,9 +1319,9 @@ struct em_hw {
#define ID_LED_RESERVED_0000 0x0000
#define ID_LED_RESERVED_FFFF 0xFFFF
#define ID_LED_DEFAULT ((ID_LED_OFF1_ON2 << 12) | \
- (ID_LED_OFF1_OFF2 << 8) | \
- (ID_LED_DEF1_DEF2 << 4) | \
- (ID_LED_DEF1_DEF2))
+ (ID_LED_OFF1_OFF2 << 8) | \
+ (ID_LED_DEF1_DEF2 << 4) | \
+ (ID_LED_DEF1_DEF2))
#define ID_LED_DEF1_DEF2 0x1
#define ID_LED_DEF1_ON2 0x2
#define ID_LED_DEF1_OFF2 0x3
@@ -1318,6 +1332,10 @@ struct em_hw {
#define ID_LED_OFF1_ON2 0x8
#define ID_LED_OFF1_OFF2 0x9
+/* Mask bits for fields in Word 0x03 of the EEPROM */
+#define EEPROM_COMPAT_SERVER 0x0400
+#define EEPROM_COMPAT_CLIENT 0x0200
+
/* Mask bits for fields in Word 0x0a of the EEPROM */
#define EEPROM_WORD0A_ILOS 0x0010
#define EEPROM_WORD0A_SWDPIO 0x01E0
@@ -1403,6 +1421,16 @@ struct em_hw {
#define FC_DEFAULT_LO_THRESH (0x4000) /* 16KB */
#define FC_DEFAULT_TX_TIMER (0x100) /* ~130 us */
+/* PCIX Config space */
+#define PCIX_COMMAND_REGISTER 0xE6
+#define PCIX_STATUS_REGISTER_LO 0xE8
+#define PCIX_STATUS_REGISTER_HI 0xEA
+
+#define PCIX_COMMAND_MMRBC_MASK 0x000C
+#define PCIX_COMMAND_MMRBC_SHIFT 0x2
+#define PCIX_STATUS_HI_MMRBC_MASK 0x0060
+#define PCIX_STATUS_HI_MMRBC_SHIFT 0x5
+
/* The number of bits that we need to shift right to move the "pause"
* bits from the EEPROM (bits 13:12) to the "pause" (bits 8:7) field
diff --git a/sys/dev/em/if_em_osdep.h b/sys/dev/em/if_em_osdep.h
index e106e04..27db87d 100644
--- a/sys/dev/em/if_em_osdep.h
+++ b/sys/dev/em/if_em_osdep.h
@@ -86,48 +86,48 @@ SUCH DAMAGE.
struct em_osdep
{
- bus_space_tag_t bus_space_tag;
- bus_space_handle_t bus_space_handle;
- struct device *dev;
+ bus_space_tag_t mem_bus_space_tag;
+ bus_space_handle_t mem_bus_space_handle;
+ struct device *dev;
};
#define E1000_READ_REG(a, reg) (\
((a)->mac_type >= em_82543) ? \
- bus_space_read_4( ((struct em_osdep *)(a)->back)->bus_space_tag, \
- ((struct em_osdep *)(a)->back)->bus_space_handle, \
+ bus_space_read_4( ((struct em_osdep *)(a)->back)->mem_bus_space_tag, \
+ ((struct em_osdep *)(a)->back)->mem_bus_space_handle, \
E1000_##reg): \
- bus_space_read_4( ((struct em_osdep *)(a)->back)->bus_space_tag, \
- ((struct em_osdep *)(a)->back)->bus_space_handle, \
+ bus_space_read_4( ((struct em_osdep *)(a)->back)->mem_bus_space_tag, \
+ ((struct em_osdep *)(a)->back)->mem_bus_space_handle, \
E1000_82542_##reg))
#define E1000_WRITE_REG(a, reg, value) (\
((a)->mac_type >= em_82543) ? \
- bus_space_write_4( ((struct em_osdep *)(a)->back)->bus_space_tag, \
- ((struct em_osdep *)(a)->back)->bus_space_handle, \
+ bus_space_write_4( ((struct em_osdep *)(a)->back)->mem_bus_space_tag, \
+ ((struct em_osdep *)(a)->back)->mem_bus_space_handle, \
E1000_##reg, value): \
- bus_space_write_4( ((struct em_osdep *)(a)->back)->bus_space_tag, \
- ((struct em_osdep *)(a)->back)->bus_space_handle, \
+ bus_space_write_4( ((struct em_osdep *)(a)->back)->mem_bus_space_tag, \
+ ((struct em_osdep *)(a)->back)->mem_bus_space_handle, \
E1000_82542_##reg, value))
#define E1000_READ_REG_ARRAY(a, reg, offset) (\
((a)->mac_type >= em_82543) ? \
- bus_space_read_4( ((struct em_osdep *)(a)->back)->bus_space_tag, \
- ((struct em_osdep *)(a)->back)->bus_space_handle, \
+ bus_space_read_4( ((struct em_osdep *)(a)->back)->mem_bus_space_tag, \
+ ((struct em_osdep *)(a)->back)->mem_bus_space_handle, \
(E1000_##reg + ((offset) << 2))): \
- bus_space_read_4( ((struct em_osdep *)(a)->back)->bus_space_tag, \
- ((struct em_osdep *)(a)->back)->bus_space_handle, \
+ bus_space_read_4( ((struct em_osdep *)(a)->back)->mem_bus_space_tag, \
+ ((struct em_osdep *)(a)->back)->mem_bus_space_handle, \
(E1000_82542_##reg + ((offset) << 2))))
#define E1000_WRITE_REG_ARRAY(a, reg, offset, value) (\
((a)->mac_type >= em_82543) ? \
- bus_space_write_4( ((struct em_osdep *)(a)->back)->bus_space_tag, \
- ((struct em_osdep *)(a)->back)->bus_space_handle, \
+ bus_space_write_4( ((struct em_osdep *)(a)->back)->mem_bus_space_tag, \
+ ((struct em_osdep *)(a)->back)->mem_bus_space_handle, \
(E1000_##reg + ((offset) << 2)), value): \
- bus_space_write_4( ((struct em_osdep *)(a)->back)->bus_space_tag, \
- ((struct em_osdep *)(a)->back)->bus_space_handle, \
+ bus_space_write_4( ((struct em_osdep *)(a)->back)->mem_bus_space_tag, \
+ ((struct em_osdep *)(a)->back)->mem_bus_space_handle, \
(E1000_82542_##reg + ((offset) << 2)), value))
OpenPOWER on IntegriCloud