ia64/xen-unstable

changeset 16417:53dc1cf50506

merge with xen-unstable.hg (staging)
author Alex Williamson <alex.williamson@hp.com>
date Wed Nov 21 09:12:06 2007 -0700 (2007-11-21)
parents 9a9ddc04eea2 05cbf512b82b
children 980b8d1a5541
files xen/include/asm-powerpc/smpboot.h xen/include/asm-x86/smpboot.h
line diff
     1.1 --- a/tools/ioemu/Makefile.target	Tue Nov 20 11:53:44 2007 -0700
     1.2 +++ b/tools/ioemu/Makefile.target	Wed Nov 21 09:12:06 2007 -0700
     1.3 @@ -399,7 +399,7 @@ VL_OBJS+= scsi-disk.o cdrom.o lsi53c895a
     1.4  VL_OBJS+= usb.o usb-hub.o usb-linux.o usb-hid.o usb-ohci.o usb-msd.o
     1.5  
     1.6  # PCI network cards
     1.7 -VL_OBJS+= ne2000.o rtl8139.o pcnet.o
     1.8 +VL_OBJS+= ne2000.o rtl8139.o pcnet.o e100.o
     1.9  
    1.10  ifeq ($(TARGET_BASE_ARCH), i386)
    1.11  # Hardware support
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/tools/ioemu/hw/e100.c	Wed Nov 21 09:12:06 2007 -0700
     2.3 @@ -0,0 +1,2464 @@
     2.4 +/*
     2.5 + * QEMU E100(i82557) ethernet card emulation
     2.6 + *
     2.7 + * This program is free software; you can redistribute it and/or modify
     2.8 + * it under the terms of the GNU General Public License as published by
     2.9 + * the Free Software Foundation; either version 2 of the License, or
    2.10 + * (at your option) any later version.
    2.11 + *
    2.12 + * This program is distributed in the hope that it will be useful,
    2.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    2.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    2.15 + * GNU General Public License for more details.
    2.16 + *
    2.17 + * You should have received a copy of the GNU General Public License
    2.18 + * along with this program; if not, write to the Free Software
    2.19 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
    2.20 + *
    2.21 + * Copyright (c) 2006-2007 Stefan Weil
    2.22 + * Copyright (c) 2006-2007 Zhang Xin(xing.z.zhang@intel.com)
    2.23 + *
    2.24 + * Support OS:
    2.25 + *      x86 linux and windows
    2.26 + *      PAE linux and windows
    2.27 + *      x86_64 linux and windows
    2.28 + *      IA64 linux and windows
    2.29 + *
    2.30 + * Untested:
    2.31 + *      Big-endian machine
    2.32 + *
    2.33 + * References:
    2.34 + *
    2.35 + * Intel 8255x 10/100 Mbps Ethernet Controller Family
    2.36 + * Open Source Software Developer Manual
    2.37 + */
    2.38 +
    2.39 +#include <assert.h>
    2.40 +#include "vl.h"
    2.41 +
    2.42 +enum
    2.43 +{
    2.44 +    E100_PCI_VENDOR_ID = 0x00,        /* 16 bits */
    2.45 +    E100_PCI_DEVICE_ID = 0x02,        /* 16 bits */
    2.46 +    E100_PCI_COMMAND = 0x04,        /* 16 bits */
    2.47 +    E100_PCI_STATUS = 0x06,            /* 16 bits */
    2.48 +    E100_PCI_REVISION_ID = 0x08,    /* 8 bits */
    2.49 +    E100_PCI_CLASS_CODE = 0x0b,        /* 8 bits */
    2.50 +    E100_PCI_SUBCLASS_CODE = 0x0a,    /* 8 bits */
    2.51 +    E100_PCI_HEADER_TYPE = 0x0e,    /* 8 bits */
    2.52 +    E100_PCI_BASE_ADDRESS_0 = 0x10,    /* 32 bits */
    2.53 +    E100_PCI_BASE_ADDRESS_1 = 0x14,    /* 32 bits */
    2.54 +    E100_PCI_BASE_ADDRESS_2 = 0x18,    /* 32 bits */
    2.55 +    E100_PCI_BASE_ADDRESS_3 = 0x1c,    /* 32 bits */
    2.56 +    E100_PCI_BASE_ADDRESS_4 = 0x20,    /* 32 bits */
    2.57 +    E100_PCI_BASE_ADDRESS_5 = 0x24    /* 32 bits */
    2.58 +}PCI_CONFIGURE_SPACE;
    2.59 +
    2.60 +#define PCI_CONFIG_8(offset, value) \
    2.61 +    (*(uint8_t *)&pci_conf[offset] = (value))
    2.62 +#define PCI_CONFIG_16(offset, value) \
    2.63 +    (*(uint16_t *)&pci_conf[offset] = cpu_to_le16(value))
    2.64 +#define PCI_CONFIG_32(offset, value) \
    2.65 +    (*(uint32_t *)&pci_conf[offset] = cpu_to_le32(value))
    2.66 +
    2.67 +// Alias for Control/Status register read/write
    2.68 +#define CSR_STATUS  scb_status
    2.69 +#define CSR_CMD scb_cmd
    2.70 +#define CSR_POINTER scb_pointer
    2.71 +#define CSR_PORT port
    2.72 +#define CSR_EEPROM eeprom_ctrl
    2.73 +#define CSR_MDI mdi_ctrl
    2.74 +#define CSR_PM pm_reg
    2.75 +
    2.76 +#define CSR(class, field)   \
    2.77 +    (s->pci_mem.csr.class.u.field)
    2.78 +#define CSR_VAL(class)  \
    2.79 +    (s->pci_mem.csr.class.val)
    2.80 +
    2.81 +#define CSR_READ(x, type)    \
    2.82 +    ({  \
    2.83 +        type t; \
    2.84 +        memcpy(&t, &s->pci_mem.mem[x], sizeof(type)); \
    2.85 +        t;  \
    2.86 +     })
    2.87 +
    2.88 +#define CSR_WRITE(x, val, type)    \
    2.89 +    ({  \
    2.90 +        type t = val; \
    2.91 +        memcpy(&s->pci_mem.mem[x], &t, sizeof(type)); \
    2.92 +     })
    2.93 +
    2.94 +#define SET_CU_STATE(val)    \
    2.95 +    (CSR(CSR_STATUS, cus) = val)
    2.96 +#define GET_CU_STATE    \
    2.97 +    (CSR(CSR_STATUS, cus))
    2.98 +
    2.99 +#define SET_RU_STATE(val)    \
   2.100 +    (CSR(CSR_STATUS, rus) = val)
   2.101 +#define GET_RU_STATE    \
   2.102 +    (CSR(CSR_STATUS, rus))
   2.103 +
   2.104 +#define KiB 1024
   2.105 +
   2.106 +#define EEPROM_SIZE     64
   2.107 +
   2.108 +#define BIT(n) (1U << (n))
   2.109 +
   2.110 +/* debug E100 card */
   2.111 +//#define DEBUG_E100
   2.112 +
   2.113 +#ifdef DEBUG_E100
   2.114 +#define logout(fmt, args...) fprintf(stderr, "EE100\t%-28s" fmt, __func__, ##args)
   2.115 +#else
   2.116 +#define logout(fmt, args...) ((void)0)
   2.117 +#endif
   2.118 +
   2.119 +#define MAX_ETH_FRAME_SIZE 1514
   2.120 +
   2.121 +/* This driver supports several different devices which are declared here. */
   2.122 +#define i82551          0x82551
   2.123 +#define i82557B         0x82557b
   2.124 +#define i82557C         0x82557c
   2.125 +#define i82558B         0x82558b
   2.126 +#define i82559C         0x82559c
   2.127 +#define i82559ER        0x82559e
   2.128 +#define i82562          0x82562
   2.129 +
   2.130 +#define PCI_MEM_SIZE            (4 * KiB)
   2.131 +#define PCI_IO_SIZE             (64)
   2.132 +#define PCI_FLASH_SIZE          (128 * KiB)
   2.133 +
   2.134 +enum
   2.135 +{
   2.136 +    OP_READ,
   2.137 +    OP_WRITE,
   2.138 +} OPERTAION_DIRECTION;
   2.139 +
   2.140 +/* The SCB accepts the following controls for the Tx and Rx units: */
   2.141 +enum
   2.142 +{
   2.143 +    CU_NOP = 0x0000,        /* No operation */
   2.144 +    CU_START = 0x0010,        /* CU start     */
   2.145 +    CU_RESUME = 0x0020,        /* CU resume    */
   2.146 +    CU_STATSADDR = 0x0040,    /* Load dump counters address */
   2.147 +    CU_SHOWSTATS = 0x0050,    /* Dump statistical counters */
   2.148 +    CU_CMD_BASE = 0x0060,    /* Load CU base address */
   2.149 +    CU_DUMPSTATS = 0x0070,    /* Dump and reset statistical counters */
   2.150 +    CU_S_RESUME = 0x00a0    /* CU static resume */
   2.151 +}CONTROL_UNIT_COMMAND;
   2.152 +
   2.153 +enum
   2.154 +{
   2.155 +    RU_NOP = 0x0000,
   2.156 +    RU_START = 0x0001,
   2.157 +    RU_RESUME = 0x0002,
   2.158 +    RU_DMA_REDIRECT = 0x0003,
   2.159 +    RU_ABORT = 0x0004,
   2.160 +    RU_LOAD_HDS = 0x0005,
   2.161 +    RU_ADDR_LOAD = 0x0006,
   2.162 +    RU_RESUMENR = 0x0007,
   2.163 +}RECEIVE_UNIT_COMMAND;
   2.164 +
   2.165 +/* SCB status word descriptions */
   2.166 +enum
   2.167 +{
   2.168 +    CU_IDLE = 0,
   2.169 +    CU_SUSPENDED = 1,
   2.170 +    CU_LPQ_ACTIVE = 2,
   2.171 +    CU_HQP_ACTIVE = 3
   2.172 +} CONTROL_UINT_STATE;
   2.173 +
   2.174 +enum
   2.175 +{
   2.176 +    RU_IDLE = 0,
   2.177 +    RU_SUSPENDED = 1,
   2.178 +    RU_NO_RESOURCES =2,
   2.179 +    RU_READY = 4
   2.180 +} RECEIVE_UNIT_STATE;
   2.181 +
   2.182 +enum
   2.183 +{
   2.184 +    PORT_SOFTWARE_RESET = 0,
   2.185 +    PORT_SELF_TEST = 1,
   2.186 +    PORT_SELECTIVE_RESET = 2,
   2.187 +    PORT_DUMP = 3,
   2.188 +    PORT_DUMP_WAKE_UP = 7,
   2.189 +}SCB_PORT_SELECTION_FUNCTION;
   2.190 +
   2.191 +enum
   2.192 +{
   2.193 +    CBL_NOP = 0,
   2.194 +    CBL_IASETUP = 1,
   2.195 +    CBL_CONFIGURE = 2,
   2.196 +    CBL_MULTCAST_ADDR_SETUP = 3,
   2.197 +    CBL_TRANSMIT = 4,
   2.198 +    CBL_LOAD_MICROCODE = 5,
   2.199 +    CBL_DUMP = 6,
   2.200 +    CBL_DIAGNOSE = 7,
   2.201 +}CBL_COMMAND;
   2.202 +
   2.203 +enum
   2.204 +{
   2.205 +    SCB_STATUS = 0,            /* SCB base + 0x00h, RU states + CU states + STAT/ACK */
   2.206 +    SCB_ACK = 1,            /* SCB ack/stat */
   2.207 +    SCB_CMD = 2,            /* RU command + CU command + S bit + M bit */
   2.208 +    SCB_INTERRUPT_MASK = 3, /* Interrupts mask bits */
   2.209 +    SCB_POINTER = 4,        /* SCB general pointer, depending on command type */
   2.210 +    SCB_PORT = 8,            /* SCB port register */
   2.211 +    SCB_EEPROM = 0xe,        /* SCB eeprom control register */
   2.212 +    SCB_MDI =0x10,            /* SCB MDI control register */
   2.213 +} CSR_OFFSETS;
   2.214 +
   2.215 +enum
   2.216 +{
   2.217 +    EEPROM_SK = 0x01,
   2.218 +    EEPROM_CS = 0x02,
   2.219 +    EEPROM_DI = 0x04,
   2.220 +    EEPROM_DO = 0x08,
   2.221 +} EEPROM_CONTROL_REGISTER;
   2.222 +
   2.223 +enum
   2.224 +{
   2.225 +    EEPROM_READ = 0x2,
   2.226 +    EEPROM_WRITE = 0x1,
   2.227 +    EEPROM_ERASE = 0x3,
   2.228 +} EEPROM_OPCODE;
   2.229 +
   2.230 +enum
   2.231 +{
   2.232 +    MDI_WRITE = 0x1,
   2.233 +    MDI_READ = 0x2,
   2.234 +} MDI_OPCODE;
   2.235 +
   2.236 +enum
   2.237 +{
   2.238 +    INT_FCP = BIT(8),
   2.239 +    INT_SWI = BIT(10),
   2.240 +    INT_MDI = BIT(11),
   2.241 +    INT_RNR = BIT(12),
   2.242 +    INT_CNA = BIT(13),
   2.243 +    INT_FR = BIT(14),
   2.244 +    INT_CX_TNO = BIT(15),
   2.245 +} E100_INTERRUPT;
   2.246 +
   2.247 +enum
   2.248 +{
   2.249 +    CSR_MEMORY_BASE,
   2.250 +    CSR_IO_BASE,
   2.251 +    FLASH_MEMORY_BASE,
   2.252 +    REGION_NUM
   2.253 +}E100_PCI_MEMORY_REGION;
   2.254 +
   2.255 +typedef struct {
   2.256 +    uint32_t tx_good_frames,        // Good frames transmitted
   2.257 +             tx_max_collisions,     // Fatal frames -- had max collisions
   2.258 +             tx_late_collisions,    // Fatal frames -- had a late coll.
   2.259 +             tx_underruns,          // Transmit underruns (fatal or re-transmit)
   2.260 +             tx_lost_crs,           // Frames transmitted without CRS
   2.261 +             tx_deferred,           // Deferred transmits
   2.262 +             tx_single_collisions,  // Transmits that had 1 and only 1 coll.
   2.263 +             tx_multiple_collisions,// Transmits that had multiple coll.
   2.264 +             tx_total_collisions,   // Transmits that had 1+ collisions.
   2.265 +
   2.266 +             rx_good_frames,        // Good frames received
   2.267 +             rx_crc_errors,         // Aligned frames that had a CRC error
   2.268 +             rx_alignment_errors,   // Receives that had alignment errors
   2.269 +             rx_resource_errors,    // Good frame dropped due to lack of resources
   2.270 +             rx_overrun_errors,     // Overrun errors - bus was busy
   2.271 +             rx_cdt_errors,         // Received frames that encountered coll.
   2.272 +             rx_short_frame_errors, // Received frames that were to short
   2.273 +
   2.274 +             complete_word;         // A005h indicates dump cmd completion,
   2.275 +                                    // A007h indicates dump and reset cmd completion.
   2.276 +
   2.277 +// TODO: Add specific field for i82558, i82559
   2.278 +} __attribute__ ((packed)) e100_stats_t;
   2.279 +
   2.280 +#define EEPROM_I82557_ADDRBIT 6
   2.281 +/* Below data is dumped from a real I82557 card */
   2.282 +static const uint16_t eeprom_i82557[] =
   2.283 +{
   2.284 +    0x300, 0xe147, 0x2fa4, 0x203, 0x0, 0x201, 0x4701, 0x0, 0x7414, 0x6207,
   2.285 +    0x4082, 0xb, 0x8086, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
   2.286 +    0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
   2.287 +    0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x128, 0x0, 0x0, 0x0, 0x0, 0x0,
   2.288 +    0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc374,
   2.289 +};
   2.290 +
   2.291 +static const uint8_t e100_pci_configure[] =
   2.292 +{
   2.293 +    0x86, 0x80, 0x29, 0x12, 0x17, 0x00, 0x90, 0x02, 0x08, 0x00, 0x00, 0x02, 0x10, 0x20, 0x00, 0x00,
   2.294 +    0x00, 0x00, 0x10, 0x50, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00,
   2.295 +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86, 0x80, 0x0b, 0x00,
   2.296 +    0x00, 0x00, 0xf0, 0xff, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x01, 0x08, 0x38,
   2.297 +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   2.298 +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   2.299 +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   2.300 +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   2.301 +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   2.302 +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   2.303 +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   2.304 +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   2.305 +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   2.306 +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x22, 0xfe,
   2.307 +    0x00, 0x40, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   2.308 +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   2.309 +};
   2.310 +
   2.311 +typedef struct
   2.312 +{
   2.313 +#define OPCODE      0xb
   2.314 +#define ADDR        0xc
   2.315 +#define DATA        0xd
   2.316 +#define NOP         0xe
   2.317 +
   2.318 +#define EEPROM_RESET_ALL      0xfe
   2.319 +#define EEPROM_SELECT_RESET   0xff
   2.320 +    uint8_t  start_bit;
   2.321 +    uint8_t  opcode;
   2.322 +    uint8_t  address;
   2.323 +    uint16_t data;  //This must be 16 bit represents a register in eeprom
   2.324 +
   2.325 +    uint32_t val;
   2.326 +    uint32_t val_len;
   2.327 +    uint8_t  val_type;  // What data type is in DI. opcode?address?data?
   2.328 +
   2.329 +    uint8_t cs;
   2.330 +    uint8_t sk;
   2.331 +
   2.332 +    // This two fileds only be reset when device init
   2.333 +    uint16_t addr_len;
   2.334 +    uint16_t contents[256]; // 256 is enough to all device(i82557 ... i82559)
   2.335 +} eeprom_t;
   2.336 +
   2.337 +// Control/Status register structure
   2.338 +typedef struct
   2.339 +{
   2.340 +    /* SCB status word */
   2.341 +    union
   2.342 +    {
   2.343 +        uint16_t val;
   2.344 +        struct
   2.345 +        {
   2.346 +            uint8_t rs1:2;  // Reserved
   2.347 +            uint8_t rus:4;  // RU status
   2.348 +            uint8_t cus:2;  // CU status
   2.349 +            uint8_t stat_ack; // Stat/ACK
   2.350 +        }u;
   2.351 +    }scb_status;
   2.352 +
   2.353 +    /* SCB command word */
   2.354 +    union
   2.355 +    {
   2.356 +        uint16_t val;
   2.357 +        struct
   2.358 +        {
   2.359 +            uint8_t ru_cmd:3;   // RU command
   2.360 +            uint8_t rs1:1;      // Reserved
   2.361 +            uint8_t cu_cmd:4;   // CU command
   2.362 +            uint8_t m:1;        // Interrup mask bit(1:mask all interrupt)
   2.363 +            uint8_t si:1;       // Use for software cause interrupt
   2.364 +            uint8_t simb:6;     // Specific interrupt mask bit
   2.365 +        }u;
   2.366 +    }scb_cmd;
   2.367 +
   2.368 +    /* SCB general pointer */
   2.369 +    union
   2.370 +    {
   2.371 +        uint32_t val;
   2.372 +        struct
   2.373 +        {
   2.374 +            uint32_t scb_ptr;
   2.375 +        }u;
   2.376 +    }scb_pointer;
   2.377 +
   2.378 +    /* Port interface */
   2.379 +    union
   2.380 +    {
   2.381 +        uint32_t val;
   2.382 +        struct
   2.383 +        {
   2.384 +            uint8_t opcode:4;   // Op code for function selection
   2.385 +            uint32_t ptr:28;    // Result pointer
   2.386 +        }u;
   2.387 +    }port;
   2.388 +
   2.389 +    uint16_t rs1;               // Reserved
   2.390 +
   2.391 +    /* EEPROM control register */
   2.392 +    union
   2.393 +    {
   2.394 +        uint16_t val;
   2.395 +        struct
   2.396 +        {
   2.397 +            uint8_t eesk:1;      // Serial clock
   2.398 +            uint8_t eecs:1;      // Chip select
   2.399 +            uint8_t eedi:1;      // Serial data in
   2.400 +            uint8_t eedo:1;      // Serial data out
   2.401 +            uint8_t rs1:4;       // Reserved
   2.402 +            uint8_t data;
   2.403 +        }u;
   2.404 +    }eeprom_ctrl;
   2.405 +
   2.406 +    /* MDI control register */
   2.407 +    union
   2.408 +    {
   2.409 +        uint32_t val;
   2.410 +        struct
   2.411 +        {
   2.412 +            uint16_t data;       // Data
   2.413 +            uint8_t regaddr:5;   // PHY register address
   2.414 +            uint8_t phyaddr:5;   // PHY address
   2.415 +            uint8_t opcode:2;    // Opcode
   2.416 +            uint8_t r:1;         // Ready
   2.417 +            uint8_t ie:1;        // Interrup enable
   2.418 +            uint8_t rs1:2;       // Reserved
   2.419 +        }u;
   2.420 +    } mdi_ctrl;
   2.421 +
   2.422 +    /* Receive byte counter register */
   2.423 +    uint32_t rx_byte_counter;
   2.424 +
   2.425 +    /* Early receive interrupt register */
   2.426 +    uint8_t early_interrupt;
   2.427 +
   2.428 +    /* Flow control register */
   2.429 +    union
   2.430 +    {
   2.431 +        uint16_t val;
   2.432 +    }flow_ctrl;
   2.433 +
   2.434 +    /* Power management driver register */
   2.435 +    union
   2.436 +    {
   2.437 +        uint8_t val;
   2.438 +        struct
   2.439 +        {
   2.440 +            uint8_t pme_s:1;     // PME status
   2.441 +            uint8_t tco_r:1;     // TCO request
   2.442 +            uint8_t f_tco_i:1;   // Force TCO indication
   2.443 +            uint8_t tco_re:1;    // TCO ready
   2.444 +            uint8_t rs1:1;       // Reserved
   2.445 +            uint8_t isp:1;       // Intersting packet
   2.446 +            uint8_t mg:1;        // Magic packet
   2.447 +            uint8_t lsci:1;      // Link status change indication
   2.448 +        }u;
   2.449 +    }pm_reg;
   2.450 +
   2.451 +    /* General control register */
   2.452 +    uint8_t gen_ctrl;
   2.453 +
   2.454 +    /* General status register */
   2.455 +    uint8_t gen_status;
   2.456 +
   2.457 +    /* These are reserved or we don't support register */
   2.458 +    uint8_t others[30];
   2.459 +} __attribute__ ((packed)) csr_t;
   2.460 +
   2.461 +typedef struct
   2.462 +{
   2.463 +    uint8_t byte_count;
   2.464 +    uint8_t rx_fifo_limit:4;
   2.465 +    uint8_t tx_fifo_limit:4;
   2.466 +    uint8_t adpt_inf_spacing;
   2.467 +    uint8_t rs1;
   2.468 +    uint8_t rx_dma_max_bytes;
   2.469 +    uint8_t tx_dma_max_bytes:7;
   2.470 +    uint8_t dmbc_en:1;
   2.471 +    uint8_t late_scb:1,
   2.472 +            rs2:1,
   2.473 +            tno_intr:1,
   2.474 +            ci_intr:1,
   2.475 +            rs3:1,
   2.476 +            rs4:1,
   2.477 +            dis_overrun_rx:1,
   2.478 +            save_bad_frame:1;
   2.479 +    uint8_t dis_short_rx:1,
   2.480 +            underrun_retry:2,
   2.481 +            rs5:5;
   2.482 +    uint8_t mii:1,
   2.483 +            rs6:7;
   2.484 +    uint8_t rs7;
   2.485 +    uint8_t rs8:3,
   2.486 +            nsai:1,
   2.487 +            preamble_len:2,
   2.488 +            loopback:2;
   2.489 +    uint8_t linear_prio:3,
   2.490 +            rs9:5;
   2.491 +    uint8_t pri_mode:1,
   2.492 +            rs10:3,
   2.493 +            interframe_spacing:4;
   2.494 +    uint16_t rs11;
   2.495 +    uint8_t promiscuous:1,
   2.496 +            broadcast_dis:1,
   2.497 +            rs12:5,
   2.498 +            crs_cdt:1;
   2.499 +    uint16_t rs13;
   2.500 +    uint8_t strip:1,
   2.501 +            padding:1,
   2.502 +            rx_crc:1,
   2.503 +            rs14:5;
   2.504 +    uint8_t rs15:6,
   2.505 +            force_fdx:1,
   2.506 +            fdx_en:1;
   2.507 +    uint8_t rs16:6,
   2.508 +            mul_ia:2;
   2.509 +    uint8_t rs17:3,
   2.510 +            mul_all:1,
   2.511 +            rs18:4;
   2.512 +} __attribute__ ((packed)) i82557_cfg_t;
   2.513 +
   2.514 +typedef struct {
   2.515 +    VLANClientState *vc;
   2.516 +    PCIDevice *pci_dev;
   2.517 +    int mmio_index;
   2.518 +    uint8_t scb_stat;           /* SCB stat/ack byte */
   2.519 +    uint32_t region_base_addr[REGION_NUM];         /* PCI region addresses */
   2.520 +    uint8_t macaddr[6];
   2.521 +    uint16_t mdimem[32];
   2.522 +    eeprom_t eeprom;
   2.523 +    uint32_t device;            /* device variant */
   2.524 +
   2.525 +    uint8_t mult_list[8];       /* Multicast address list */
   2.526 +    int is_multcast_enable;
   2.527 +
   2.528 +    /* (cu_base + cu_offset) address the next command block in the command block list. */
   2.529 +    uint32_t cu_base;           /* CU base address */
   2.530 +    uint32_t cu_offset;         /* CU address offset */
   2.531 +    uint32_t cu_next;           /* Point to next command when CU go to suspend */
   2.532 +
   2.533 +    /* (ru_base + ru_offset) address the RFD in the Receive Frame Area. */
   2.534 +    uint32_t ru_base;           /* RU base address */
   2.535 +    uint32_t ru_offset;         /* RU address offset */
   2.536 +
   2.537 +    uint32_t statsaddr;         /* pointer to e100_stats_t */
   2.538 +
   2.539 +    e100_stats_t statistics;        /* statistical counters */
   2.540 +
   2.541 +    /* Configuration bytes. */
   2.542 +    i82557_cfg_t config;
   2.543 +
   2.544 +    /* FIFO buffer of card. The packet that need to be sent buffered in it */
   2.545 +    uint8_t pkt_buf[MAX_ETH_FRAME_SIZE+4];
   2.546 +    /* Data length in FIFO buffer */
   2.547 +    int pkt_buf_len;
   2.548 +
   2.549 +    /* Data in mem is always in the byte order of the controller (le). */
   2.550 +    union
   2.551 +    {
   2.552 +        csr_t csr;
   2.553 +        uint8_t mem[PCI_MEM_SIZE];
   2.554 +    }pci_mem;
   2.555 +
   2.556 +} E100State;
   2.557 +
   2.558 +/* CB structure, filled by device driver
   2.559 + * This is a common structure of CB. In some
   2.560 + * special case such as TRANSMIT command, the
   2.561 + * reserved field will be used.
   2.562 + */
   2.563 +struct  control_block
   2.564 +{
   2.565 +    uint16_t rs1:13;            /* reserved */
   2.566 +    uint8_t ok:1;               /* 1:command executed without error, otherwise 0 */
   2.567 +    uint8_t rs2:1;
   2.568 +    uint8_t c:1;                /* execution status. set by device, clean by software */
   2.569 +    uint8_t cmd:3;              /* command */
   2.570 +    uint16_t rs3:10;            /* most time equal to 0 */
   2.571 +    uint8_t i:1;                /* whether trigger interrupt after execution. 1:yes; 0:no */
   2.572 +    uint8_t s:1;                /* suspend */
   2.573 +    uint8_t el:1;               /* end flag */
   2.574 +    uint32_t link_addr;
   2.575 +} __attribute__ ((packed));
   2.576 +
   2.577 +typedef struct
   2.578 +{
   2.579 +    uint32_t tx_desc_addr;      /* transmit buffer decsriptor array address. */
   2.580 +    uint16_t tcb_bytes:14;         /* transmit command block byte count (in lower 14 bits)*/
   2.581 +    uint8_t rs1:1;
   2.582 +    uint8_t eof:1;
   2.583 +    uint8_t tx_threshold;       /* transmit threshold */
   2.584 +    uint8_t tbd_num;          /* TBD number */
   2.585 +} __attribute__ ((packed)) tbd_t;
   2.586 +
   2.587 +/* Receive frame descriptore structure */
   2.588 +typedef struct
   2.589 +{
   2.590 +    uint16_t status:13;     // Result of receive opration
   2.591 +    uint8_t ok:1;           // 1:receive without error, otherwise 0
   2.592 +    uint8_t rs1:1;
   2.593 +    uint8_t c:1;            // 1:receive complete
   2.594 +    uint8_t rs2:3;
   2.595 +    uint8_t sf:1;           // 0:simplified mode
   2.596 +    uint8_t h:1;            // 1:header RFD
   2.597 +    uint16_t rs3:9;
   2.598 +    uint8_t s:1;            // 1:go to suspend
   2.599 +    uint8_t el:1;           // 1:last RFD
   2.600 +    uint32_t link_addr;     // Add on RU base point to next RFD
   2.601 +    uint32_t rs4;
   2.602 +    uint16_t count:14;      // Number of bytes written into data area
   2.603 +    uint8_t f:1;            // Set by device when count field update
   2.604 +    uint8_t eof:1;          // Set by device when placing data into data area complete
   2.605 +    uint16_t size:14;       // Buffer size (even number)
   2.606 +    uint8_t rs5:2;
   2.607 +} __attribute__ ((packed)) rfd_t;
   2.608 +
   2.609 +enum
   2.610 +{
   2.611 +    RX_COLLISION = BIT(0),  // 1:Receive collision detected
   2.612 +    RX_IA_MATCH = BIT(1),      // 0:Receive frame match individual address
   2.613 +    RX_NO_MATCH = BIT(2), // 1:Receive frame match no address
   2.614 +    RX_ERR = BIT(4),        // 1:Receive frame error
   2.615 +    RX_TYPE = BIT(5),       // 1:Receive frame is a type frame
   2.616 +    RX_SHORT = BIT(7),      // 1:Receive frame is too short
   2.617 +    RX_DMA_ERR = BIT(8),
   2.618 +    RX_LARGE = BIT(9),      // 1:Receive frame is too large
   2.619 +    RX_CRC_ERR = BIT(10),
   2.620 +} RFD_STATUS;
   2.621 +
   2.622 +typedef struct PCIE100State {
   2.623 +    PCIDevice dev;
   2.624 +    E100State e100;
   2.625 +} PCIE100State;
   2.626 +
   2.627 +/* Default values for MDI (PHY) registers */
   2.628 +static const uint16_t e100_mdi_default[] = {
   2.629 +    /* MDI Registers 0 - 6, 7 */
   2.630 +    0x3000, 0x780d, 0x02a8, 0x0154, 0x05e1, 0x0000, 0x0000, 0x0000,
   2.631 +    /* MDI Registers 8 - 15 */
   2.632 +    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
   2.633 +    /* MDI Registers 16 - 31 */
   2.634 +    0x0003, 0x0000, 0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
   2.635 +    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
   2.636 +};
   2.637 +
   2.638 +static const uint8_t broadcast_macaddr[6] =
   2.639 +    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
   2.640 +
   2.641 +/* Debugging codes */
   2.642 +#ifdef  DEBUG_E100
   2.643 +
   2.644 +static void e100_dump(char *comment, uint8_t *info, int len)
   2.645 +{
   2.646 +    int i;
   2.647 +
   2.648 +    if ( !comment || !info )
   2.649 +        return;
   2.650 +
   2.651 +    fprintf(stderr, "EE100\t%-24s%s", __func__, comment);
   2.652 +    for ( i=0; i<len; i++ )
   2.653 +        fprintf(stderr, "%x ", info[i]);
   2.654 +
   2.655 +    fprintf(stderr, "\n");
   2.656 +}
   2.657 +
   2.658 +static const char *regname[] =
   2.659 +{
   2.660 +    [0] = "SCB Status", [1] = "SCB Ack",
   2.661 +    [2] = "SCB Cmd", [3] = "SCB Interrupt Mask",
   2.662 +    [4] = "SCB Pointer", [8] = "SCB Port",
   2.663 +    [0xc] = "SCB Flash", [0xe] = "SCB Eeprom",
   2.664 +    [0x10] = "SCB Ctrl MDI", [0x14] = "SCB Early RX",
   2.665 +};
   2.666 +#define SCBNAME(x)    \
   2.667 +    ( (x) < (sizeof(regname) / sizeof(regname[0])) ? regname[(x)] : "Unknown SCB Register" )
   2.668 +
   2.669 +static const char *cb_cmd_name[] =
   2.670 +{
   2.671 +    [CBL_NOP] = "NOP", [CBL_IASETUP] = "Individual address setup",
   2.672 +    [CBL_CONFIGURE] = "Configure", [CBL_MULTCAST_ADDR_SETUP] = "Set Multcast address list",
   2.673 +    [CBL_TRANSMIT] = "Transmit", [CBL_LOAD_MICROCODE] = "Load microcode",
   2.674 +    [CBL_DUMP] = "Dump", [CBL_DIAGNOSE] = "Diagnose",
   2.675 +};
   2.676 +#define CB_CMD_NAME(x)  \
   2.677 +    ( (x) < (sizeof(cb_cmd_name) / sizeof(cb_cmd_name[0])) ? cb_cmd_name[(x)] : "Unknown CB command" )
   2.678 +
   2.679 +static const char *eeprom_opcode_name[] =
   2.680 +{
   2.681 +    [0] = "Unknow", [EEPROM_WRITE] = "Write",
   2.682 +    [EEPROM_READ] = "Read", [EEPROM_ERASE] = "Erase",
   2.683 +};
   2.684 +#define EEPROM_OPCODE_NAME(x)   \
   2.685 +    ( (x) < (sizeof(eeprom_opcode_name) / sizeof(eeprom_opcode_name[0])) ?  \
   2.686 +      eeprom_opcode_name[(x)] : "Unknown" )
   2.687 +
   2.688 +static struct eeprom_trace_data
   2.689 +{
   2.690 +    uint8_t eedo[256];
   2.691 +    uint8_t di[256];
   2.692 +    int op;
   2.693 +    int i;
   2.694 +    uint32_t data;
   2.695 +}etd = {.op = NOP};
   2.696 +
   2.697 +static void eeprom_trace(int eedo, int di, int dir, int next_op, int clr)
   2.698 +{
   2.699 +    int i;
   2.700 +
   2.701 +    if ( clr )
   2.702 +    {
   2.703 +        char *opname = NULL;
   2.704 +
   2.705 +        switch ( etd.op )
   2.706 +        {
   2.707 +            case NOP:
   2.708 +                break;
   2.709 +            case OPCODE:
   2.710 +                opname = "opcode";
   2.711 +                break;
   2.712 +            case ADDR:
   2.713 +                opname = "address";
   2.714 +                break;
   2.715 +            case DATA:
   2.716 +                opname = "data transfer";
   2.717 +                break;
   2.718 +            default:
   2.719 +                opname = "Unknown";
   2.720 +        }
   2.721 +
   2.722 +        if ( opname )
   2.723 +        {
   2.724 +            logout("EEPROM trace:\n");
   2.725 +            fprintf(stderr, "\toperation: %s\n", opname);
   2.726 +            fprintf(stderr, "\tDI track:");
   2.727 +            for ( i=0; i<etd.i; i++ )
   2.728 +                fprintf(stderr, "%x ", etd.di[i]);
   2.729 +            fprintf(stderr, "\n\tDO track:");
   2.730 +            for ( i=0; i<etd.i; i++ )
   2.731 +                fprintf(stderr, "%x ", etd.eedo[i]);
   2.732 +            fprintf(stderr, "\n\tData:%#x\n", etd.data);
   2.733 +        }
   2.734 +
   2.735 +
   2.736 +        memset(&etd, 0x0, sizeof(etd));
   2.737 +        etd.op = next_op;
   2.738 +
   2.739 +        return;
   2.740 +    }
   2.741 +
   2.742 +    etd.eedo[etd.i] = eedo;
   2.743 +    etd.di[etd.i] = di;
   2.744 +    etd.i ++;
   2.745 +    if ( dir == EEPROM_READ && etd.op == DATA )
   2.746 +        etd.data = (etd.data << 1) | eedo;
   2.747 +    else
   2.748 +        etd.data = (etd.data << 1) | di;
   2.749 +}
   2.750 +
   2.751 +#define INT_NAME(x) \
   2.752 +    ({  \
   2.753 +     char *name = NULL; \
   2.754 +     switch (x) \
   2.755 +     {  \
   2.756 +     case INT_FCP:  \
   2.757 +            name = "FCP";   \
   2.758 +            break;  \
   2.759 +     case INT_SWI:  \
   2.760 +            name = "SWI";   \
   2.761 +            break;  \
   2.762 +     case INT_MDI:  \
   2.763 +            name = "MDI";   \
   2.764 +            break;  \
   2.765 +     case INT_RNR:  \
   2.766 +            name = "RNR";   \
   2.767 +            break;  \
   2.768 +     case INT_CNA:  \
   2.769 +            name = "CNA";   \
   2.770 +            break;  \
   2.771 +     case INT_FR:   \
   2.772 +            name = "FR";    \
   2.773 +            break;  \
   2.774 +     case INT_CX_TNO:   \
   2.775 +            name ="CX/TNO"; \
   2.776 +            break;  \
   2.777 +     default:   \
   2.778 +            name ="Unknown"; \
   2.779 +     }  \
   2.780 +     name;  \
   2.781 +     })
   2.782 +
   2.783 +#else
   2.784 +static void e100_dump(char *comment, uint8_t *info, int len) {}
   2.785 +static void eeprom_trace(int eedo, int di, int dir, int next_op, int clr) {}
   2.786 +#endif
   2.787 +
   2.788 +static void pci_reset(E100State * s)
   2.789 +{
   2.790 +    uint8_t *pci_conf = s->pci_dev->config;
   2.791 +
   2.792 +    memcpy(pci_conf, &e100_pci_configure[0], sizeof(e100_pci_configure));
   2.793 +    logout("%p\n", s);
   2.794 +
   2.795 +    /* I82557 */
   2.796 +    PCI_CONFIG_8(E100_PCI_REVISION_ID, 0x01);
   2.797 +
   2.798 +    PCI_CONFIG_8(0x3c, 0x0);
   2.799 +
   2.800 +}
   2.801 +
   2.802 +static void e100_selective_reset(E100State * s)
   2.803 +{
   2.804 +
   2.805 +    memset(s->pci_mem.mem, 0x0, sizeof(s->pci_mem.mem));
   2.806 +    // Set RU/CU to idle, maintain the register mentioned in spec,
   2.807 +    SET_CU_STATE(CU_IDLE);
   2.808 +    SET_RU_STATE(RU_IDLE);
   2.809 +    logout("CU and RU go to idle\n");
   2.810 +
   2.811 +    s->ru_offset = 0;
   2.812 +    s->cu_offset = 0;
   2.813 +    s->cu_next = 0;
   2.814 +
   2.815 +    // For 82557, special interrupt bits are all 1
   2.816 +    CSR(CSR_CMD, simb) = 0x3f;
   2.817 +    // Set PHY to 1
   2.818 +    CSR_VAL(CSR_MDI) |= BIT(21);
   2.819 +
   2.820 +    /* Initialize EEDO bit to 1. Due to driver would detect dummy 0 at
   2.821 +     * EEDO bit, so initialize it to 1 is safety a way.
   2.822 +     */
   2.823 +    CSR(CSR_EEPROM, eedo) = 1;
   2.824 +    // no pending interrupts
   2.825 +    s->scb_stat = 0;
   2.826 +
   2.827 +    return;
   2.828 +}
   2.829 +
   2.830 +static void e100_software_reset(E100State *s)
   2.831 +{
   2.832 +    memset(s->pci_mem.mem, 0x0, sizeof(s->pci_mem.mem));
   2.833 +    // Clear multicast list
   2.834 +    memset(s->mult_list, 0x0, sizeof(s->mult_list));
   2.835 +    // Set MDI register to default value
   2.836 +    memcpy(&s->mdimem[0], &e100_mdi_default[0], sizeof(s->mdimem));
   2.837 +    s->is_multcast_enable = 1;
   2.838 +    /* Clean FIFO buffer */
   2.839 +    memset(s->pkt_buf, 0x0, sizeof(s->pkt_buf));
   2.840 +    s->pkt_buf_len = 0;
   2.841 +
   2.842 +    memset(&s->statistics, 0x0, sizeof(s->statistics));
   2.843 +    e100_selective_reset(s);
   2.844 +    return;
   2.845 +}
   2.846 +
   2.847 +static void e100_reset(void *opaque)
   2.848 +{
   2.849 +    E100State *s = (E100State *) opaque;
   2.850 +    logout("%p\n", s);
   2.851 +    e100_software_reset(s);
   2.852 +}
   2.853 +
   2.854 +
   2.855 +static void e100_save(QEMUFile * f, void *opaque)
   2.856 +{
   2.857 +    //TODO
   2.858 +    return;
   2.859 +}
   2.860 +
   2.861 +static int e100_load(QEMUFile * f, void *opaque, int version_id)
   2.862 +{
   2.863 +    //TODO
   2.864 +    return 0;
   2.865 +}
   2.866 +
   2.867 +/* Interrupt functions */
   2.868 +static void e100_interrupt(E100State *s, uint16_t int_type)
   2.869 +{
   2.870 +
   2.871 +    //TODO: Add another i8255x card supported mask bit
   2.872 +    if ( !CSR(CSR_CMD,m) )
   2.873 +    {
   2.874 +        //Set bit in stat/ack, so driver can no what interrupt happen
   2.875 +        CSR_VAL(CSR_STATUS) |= int_type;
   2.876 +        s->scb_stat = CSR(CSR_STATUS, stat_ack);
   2.877 +
   2.878 +        /* SCB maske and SCB Bit M do not disable interrupt. */
   2.879 +        logout("Trigger an interrupt(type = %s(%#x), SCB Status = %#x)\n",
   2.880 +                INT_NAME(int_type), int_type, CSR_VAL(CSR_STATUS));
   2.881 +        pci_set_irq(s->pci_dev, 0, 1);
   2.882 +    }
   2.883 +}
   2.884 +
   2.885 +static void e100_interrupt_ack(E100State * s, uint8_t ack)
   2.886 +{
   2.887 +
   2.888 +    /* Ignore acknowledege if driver write 0 to ack or
   2.889 +     * according interrupt bit is not set
   2.890 +     */
   2.891 +    if ( !ack || !(s->scb_stat & ack) )
   2.892 +    {
   2.893 +        logout("Illegal interrupt ack(ack=%#x, SCB Stat/Ack=%#x), ignore it\n",
   2.894 +                ack, s->scb_stat);
   2.895 +        // Due to we do write operation before e100_execute(), so
   2.896 +        // we must restore value of ack field here
   2.897 +        CSR(CSR_STATUS, stat_ack) = s->scb_stat;
   2.898 +        return;
   2.899 +    }
   2.900 +
   2.901 +    s->scb_stat &= ~ack;
   2.902 +    CSR(CSR_STATUS, stat_ack) = s->scb_stat;
   2.903 +
   2.904 +    logout("Interrupt ack(name=%s,val=%#x)\n", INT_NAME(({uint16_t bit = ack<<8;bit;})),ack);
   2.905 +    if ( !s->scb_stat )
   2.906 +    {
   2.907 +        logout("All interrupts are acknowledeged, de-assert interrupt line\n");
   2.908 +        pci_set_irq(s->pci_dev, 0, 0);
   2.909 +    }
   2.910 +}
   2.911 +
   2.912 +static void e100_self_test(uint32_t res_addr)
   2.913 +{
   2.914 +    struct
   2.915 +    {
   2.916 +        uint32_t st_sign;           /* Self Test Signature */
   2.917 +        uint32_t st_result;         /* Self Test Results */
   2.918 +    } test_res;
   2.919 +
   2.920 +    test_res.st_sign = (uint32_t)-1;
   2.921 +    test_res.st_result = 0; // Our self test always success
   2.922 +    cpu_physical_memory_write(res_addr, (uint8_t *)&test_res, sizeof(test_res));
   2.923 +
   2.924 +    logout("Write self test result to %#x\n", res_addr);
   2.925 +}
   2.926 +
   2.927 +static void scb_port_func(E100State *s, uint32_t val, int dir)
   2.928 +{
   2.929 +#define PORT_SELECTION_MASK 0xfU
   2.930 +
   2.931 +    uint32_t sel = val & PORT_SELECTION_MASK;
   2.932 +
   2.933 +    switch ( sel )
   2.934 +    {
   2.935 +        case PORT_SOFTWARE_RESET:
   2.936 +            logout("do PORT_SOFTWARE_RESET!\n");
   2.937 +            e100_software_reset(s);
   2.938 +            break;
   2.939 +        case PORT_SELF_TEST:
   2.940 +            e100_self_test(val & ~PORT_SELECTION_MASK);
   2.941 +            logout("do PORT_SELF_TEST!\n");
   2.942 +            break;
   2.943 +        case PORT_SELECTIVE_RESET:
   2.944 +            logout("do PORT_SELECTIVE_RESET!\n");
   2.945 +            e100_selective_reset(s);
   2.946 +            break;
   2.947 +        case PORT_DUMP:
   2.948 +            logout("do PORT_SOFTWARE_RESET!\n");
   2.949 +            break;
   2.950 +        case PORT_DUMP_WAKE_UP:
   2.951 +            logout("do PORT_SOFTWARE_RESET!\n");
   2.952 +            break;
   2.953 +        default:
   2.954 +            logout("Unkonw SCB port command(selection function = %#x)\n", sel);
   2.955 +    }
   2.956 +}
   2.957 +
   2.958 +static void e100_write_mdi(E100State *s, uint32_t val)
   2.959 +{
   2.960 +    uint32_t ie = (val & 0x20000000) >> 29;
   2.961 +    uint32_t opcode = (val & 0x0c000000) >> 26;
   2.962 +    uint32_t phyaddr = (val & 0x03e00000) >> 21;
   2.963 +    uint32_t regaddr = (val & 0x001f0000) >> 16;
   2.964 +    uint32_t data = val & 0x0000ffff;
   2.965 +
   2.966 +    logout("Write MDI:\n"
   2.967 +           "\topcode:%#x\n"
   2.968 +           "\tphy address:%#x\n"
   2.969 +           "\treg address:%#x\n"
   2.970 +           "\tie:%#x\n"
   2.971 +           "\tdata:%#x\n",
   2.972 +           opcode, phyaddr, regaddr, ie, data);
   2.973 +
   2.974 +    /* We use default value --- PHY1
   2.975 +     * If driver operate on other PHYs, do nothing and
   2.976 +     * deceive it that the operation is finished
   2.977 +     */
   2.978 +    if ( phyaddr != 1 )
   2.979 +    {
   2.980 +        logout("Unsupport PHY address(phy = %#x)\n", phyaddr);
   2.981 +        goto done;
   2.982 +    }
   2.983 +
   2.984 +    // 1: MDI write
   2.985 +    // 2: MDI read
   2.986 +    if ( opcode != MDI_WRITE && opcode != MDI_READ )
   2.987 +    {
   2.988 +        logout("Invalid Opcode(opcode = %#x)\n", opcode);
   2.989 +        return;
   2.990 +    }
   2.991 +
   2.992 +    // Current only support MDI generic registers.
   2.993 +    if ( regaddr > 6 )
   2.994 +    {
   2.995 +        logout("Invalid phy register index( phy register addr = %#x)\n", regaddr);
   2.996 +    }
   2.997 +
   2.998 +    if ( opcode == MDI_WRITE )
   2.999 +    {
  2.1000 +        // MDI write
  2.1001 +        switch ( regaddr )
  2.1002 +        {
  2.1003 +            case 0:    // Control Register
  2.1004 +                if ( data & 0x8000 ) // Reset
  2.1005 +                {
  2.1006 +                    /* Reset status and control registers to default. */
  2.1007 +                    s->mdimem[0] = e100_mdi_default[0];
  2.1008 +                    s->mdimem[1] = e100_mdi_default[1];
  2.1009 +                    data = s->mdimem[regaddr];
  2.1010 +                }
  2.1011 +                else
  2.1012 +                {
  2.1013 +                    /* Restart Auto Configuration = Normal Operation */
  2.1014 +                    data &= ~0x0200;
  2.1015 +                }
  2.1016 +                break;
  2.1017 +            case 1:    // Status Register
  2.1018 +                logout("Invalid write on readonly register(opcode = %#x)\n", opcode);
  2.1019 +                data = s->mdimem[regaddr];
  2.1020 +                break;
  2.1021 +            case 2:
  2.1022 +            case 3:
  2.1023 +            case 4:
  2.1024 +            case 5:
  2.1025 +            case 6:
  2.1026 +                break;
  2.1027 +        }
  2.1028 +        s->mdimem[regaddr] = data;
  2.1029 +        logout("MDI WRITE: reg = %#x, data = %#x\n", regaddr, data);
  2.1030 +    }
  2.1031 +    else if ( opcode == MDI_READ )
  2.1032 +    {
  2.1033 +        // MDI read
  2.1034 +        switch ( regaddr )
  2.1035 +        {
  2.1036 +            case 0: // Control Register
  2.1037 +                if ( data & 0x8000 ) // Reset
  2.1038 +                {
  2.1039 +                    /* Reset status and control registers to default. */
  2.1040 +                    s->mdimem[0] = e100_mdi_default[0];
  2.1041 +                    s->mdimem[1] = e100_mdi_default[1];
  2.1042 +                }
  2.1043 +                break;
  2.1044 +            case 1: // Status Register
  2.1045 +                // Auto Negotiation complete, set sticky bit to 1
  2.1046 +                s->mdimem[regaddr] |= 0x0026;
  2.1047 +                break;
  2.1048 +            case 2: // PHY Identification Register (Word 1)
  2.1049 +            case 3: // PHY Identification Register (Word 2)
  2.1050 +                break;
  2.1051 +            case 5: // Auto-Negotiation Link Partner Ability Register
  2.1052 +                s->mdimem[regaddr] = 0x41fe;
  2.1053 +                break;
  2.1054 +            case 6: // Auto-Negotiation Expansion Register
  2.1055 +                s->mdimem[regaddr] = 0x0001;
  2.1056 +                break;
  2.1057 +        }
  2.1058 +        data = s->mdimem[regaddr];
  2.1059 +        logout("MDI READ: reg = %#x, data = %#x\n", regaddr, data);
  2.1060 +    }
  2.1061 +
  2.1062 +    /* Emulation takes no time to finish MDI transaction.
  2.1063 +     * Set MDI bit in SCB status register. */
  2.1064 +done:
  2.1065 +    val |= BIT(28);
  2.1066 +    val = (val & 0xffff0000) + data;
  2.1067 +    CSR_WRITE(SCB_MDI, val, uint32_t);
  2.1068 +
  2.1069 +    if ( ie )
  2.1070 +        e100_interrupt(s, (uint16_t)INT_MDI);
  2.1071 +}
  2.1072 +
  2.1073 +static void scb_mdi_func(E100State *s, uint32_t val, int dir)
  2.1074 +{
  2.1075 +    if ( dir == OP_READ )
  2.1076 +        // Do nothing, just tell driver we are ready
  2.1077 +        CSR_VAL(CSR_MDI) |= BIT(28);
  2.1078 +    else if ( dir == OP_WRITE )
  2.1079 +        e100_write_mdi(s, val);
  2.1080 +    else
  2.1081 +        logout("Invalid operation direction(dir=%x)\n", dir);
  2.1082 +
  2.1083 +}
  2.1084 +
  2.1085 +static void eeprom_reset(E100State *s, int type)
  2.1086 +{
  2.1087 +    eeprom_t *e = &s->eeprom;
  2.1088 +
  2.1089 +    if ( type == EEPROM_RESET_ALL )
  2.1090 +    {
  2.1091 +        memset(e, 0x0, sizeof(eeprom_t));
  2.1092 +        e->val_type = NOP;
  2.1093 +        logout("EEPROM reset all\n");
  2.1094 +        return;
  2.1095 +    }
  2.1096 +
  2.1097 +    CSR(CSR_EEPROM, eedo) = 1;
  2.1098 +    e->start_bit = 0;
  2.1099 +    e->opcode = 0;
  2.1100 +    e->address = 0;
  2.1101 +    e->data = 0;
  2.1102 +
  2.1103 +    e->val = 0;
  2.1104 +    e->val_len = 0;
  2.1105 +    e->val_type = NOP;
  2.1106 +
  2.1107 +    e->cs = 0;
  2.1108 +    e->sk = 0;
  2.1109 +    logout("EEPROM select reset\n");
  2.1110 +}
  2.1111 +
  2.1112 +static void do_eeprom_op(E100State *s, eeprom_t *e, int cs, int sk, int di, int dir)
  2.1113 +{
  2.1114 +    int assert_cs = (cs == 1 && e->cs == 0);
  2.1115 +    int de_assert_cs = (cs == 0 && e->cs == 1);
  2.1116 +    int de_assert_sk = (sk == 0 && e->sk == 1);
  2.1117 +
  2.1118 +    // Chip select is not be enabled
  2.1119 +    if ( cs == 0 && e->cs == 0 )
  2.1120 +    {
  2.1121 +        logout("Invalid EECS signal\n");
  2.1122 +        return;
  2.1123 +    }
  2.1124 +
  2.1125 +    // update state
  2.1126 +    e->cs = cs;
  2.1127 +    e->sk = sk;
  2.1128 +
  2.1129 +    // Do nothing
  2.1130 +    if ( assert_cs )
  2.1131 +    {
  2.1132 +        logout("EECS assert\n");
  2.1133 +        return;
  2.1134 +    }
  2.1135 +
  2.1136 +    // Complete one command
  2.1137 +    if ( de_assert_cs )
  2.1138 +    {
  2.1139 +        if ( e->val_type == DATA && e->opcode == EEPROM_WRITE )
  2.1140 +        {
  2.1141 +            e->data = e->val;
  2.1142 +            memcpy((void *)((unsigned long)e->contents + e->address),
  2.1143 +                    &e->data, sizeof(e->data));
  2.1144 +            logout("EEPROM write complete(data=%#x)\n", e->data);
  2.1145 +        }
  2.1146 +        eeprom_trace(0,0,0,NOP,1);
  2.1147 +        eeprom_reset(s, EEPROM_SELECT_RESET);
  2.1148 +        logout("EECS de-asserted\n");
  2.1149 +        return;
  2.1150 +    }
  2.1151 +
  2.1152 +    // Chip is selected and serial clock is change, so the operation is vaild
  2.1153 +    if ( cs == 1 && de_assert_sk == 1)
  2.1154 +    {
  2.1155 +        // Set start bit
  2.1156 +        if ( e->start_bit == 0 && di == 1 )
  2.1157 +        {
  2.1158 +             e->start_bit = di;
  2.1159 +             e->val_len = 0;
  2.1160 +             e->val = 0;
  2.1161 +             e->val_type = OPCODE;
  2.1162 +
  2.1163 +             eeprom_trace(0,0,0,OPCODE,1);
  2.1164 +             logout("EEPROM start bit set\n");
  2.1165 +             return;
  2.1166 +        }
  2.1167 +        // Data in DI is vaild
  2.1168 +        else if ( e->start_bit == 1 )
  2.1169 +        {
  2.1170 +            // If current operation is eeprom read, ignore DI
  2.1171 +            if ( !(e->val_type == DATA && e->opcode == EEPROM_READ) )
  2.1172 +            {
  2.1173 +                e->val = (e->val << 1) | di;
  2.1174 +                e->val_len ++;
  2.1175 +            }
  2.1176 +
  2.1177 +            switch ( e->val_type )
  2.1178 +            {
  2.1179 +                // Get the opcode.
  2.1180 +                case OPCODE:
  2.1181 +                    eeprom_trace(CSR(CSR_EEPROM, eedo), di, e->opcode, 0, 0);
  2.1182 +                    if ( e->val_len  == 2 )
  2.1183 +                    {
  2.1184 +                        e->opcode = e->val;
  2.1185 +                        e->val = 0;
  2.1186 +                        e->val_len = 0;
  2.1187 +                        e->val_type = ADDR;
  2.1188 +
  2.1189 +                        eeprom_trace(0,0,0,ADDR,1);
  2.1190 +                        logout("EEPROM get opcode(opcode name=%s,opcode=%#x )\n",
  2.1191 +                                EEPROM_OPCODE_NAME(e->opcode), e->opcode);
  2.1192 +                    }
  2.1193 +                    break;
  2.1194 +                // Get address
  2.1195 +                case ADDR:
  2.1196 +                    eeprom_trace(CSR(CSR_EEPROM, eedo), di, e->opcode, 0, 0);
  2.1197 +                    if ( e->val_len == e->addr_len )
  2.1198 +                    {
  2.1199 +                        e->address = e->val;
  2.1200 +                        e->val = 0;
  2.1201 +                        e->val_len = 0;
  2.1202 +                        e->val_type = DATA;
  2.1203 +
  2.1204 +                        // We prepare data eary for later read operation
  2.1205 +                        if ( e->opcode == EEPROM_READ )
  2.1206 +                        {
  2.1207 +                            memcpy(&e->data, (void *)(e->contents + e->address),
  2.1208 +                                    sizeof(e->data));
  2.1209 +                            logout("EEPROM prepare data to read(addr=%#x,data=%#x)\n", 
  2.1210 +                                    e->address, e->data);
  2.1211 +                        }
  2.1212 +
  2.1213 +                        // Write dummy 0 to response to driver the address is written complete
  2.1214 +                        CSR(CSR_EEPROM, eedo) = 0;
  2.1215 +                        eeprom_trace(0,0,0,DATA,1);
  2.1216 +                        logout("EEPROM get address(addr=%#x)\n", e->address);
  2.1217 +                    }
  2.1218 +                    break;
  2.1219 +                // Only do data out operation
  2.1220 +                case DATA:
  2.1221 +                    if ( e->opcode == EEPROM_READ )
  2.1222 +                    {
  2.1223 +                        // Start from the most significant bit
  2.1224 +                        //uint16_t t = ((e->data & (1<<(sizeof(e->data)*8 - e->val_len - 1))) != 0);
  2.1225 +                        uint16_t t = !!(e->data & (0x8000U >> e->val_len));
  2.1226 +
  2.1227 +                        CSR(CSR_EEPROM, eedo) = t;
  2.1228 +
  2.1229 +                        logout("EEPROM read(reg address=%#x, reg val=%#x, do=%#x, len=%#x)\n", 
  2.1230 +                                e->address, e->data, t, e->val_len);
  2.1231 +
  2.1232 +                        if ( e->val_len > sizeof(e->data)*8 )
  2.1233 +                        {
  2.1234 +                            /* Driver may do more write op to de-assert EESK,
  2.1235 +                             * So we let EEPROM go to idle after a register be
  2.1236 +                             * read complete
  2.1237 +                             */
  2.1238 +                            e->val_type = NOP;
  2.1239 +                            logout("Read complete\n");
  2.1240 +
  2.1241 +                            break;
  2.1242 +                        }
  2.1243 +
  2.1244 +                        e->val_len ++;
  2.1245 +                    }
  2.1246 +                    eeprom_trace(CSR(CSR_EEPROM, eedo), di, e->opcode, 0, 0);
  2.1247 +                    // Do eerpom write when CS de-assert
  2.1248 +                    break;
  2.1249 +                default:
  2.1250 +                    break;
  2.1251 +            }
  2.1252 +        }
  2.1253 +    }
  2.1254 +
  2.1255 +    return;
  2.1256 +}
  2.1257 +
  2.1258 +
  2.1259 +static void scb_eeprom_func(E100State *s, uint32_t val, int dir)
  2.1260 +{
  2.1261 +    int eecs = ((val & EEPROM_CS) != 0);
  2.1262 +    int eesk = ((val & EEPROM_SK) != 0);
  2.1263 +    int eedi = ((val & EEPROM_DI) != 0);
  2.1264 +
  2.1265 +    logout("EEPROM: Old(cs=%#x, sk=%#x), New(cs=%#x, sk=%#x, di=%#x)\n", 
  2.1266 +            s->eeprom.cs, s->eeprom.sk, eecs, eesk, eedi);
  2.1267 +
  2.1268 +    do_eeprom_op(s, &s->eeprom, eecs, eesk, eedi, dir);
  2.1269 +
  2.1270 +    return;
  2.1271 +}
  2.1272 +
  2.1273 +static void e100_ru_command(E100State *s, uint8_t val)
  2.1274 +{
  2.1275 +    switch ( val )
  2.1276 +    {
  2.1277 +        case RU_NOP:
  2.1278 +            /* Will not be here */
  2.1279 +            break;
  2.1280 +        case RU_START:
  2.1281 +            /* RU start */
  2.1282 +
  2.1283 +            SET_RU_STATE(RU_READY);
  2.1284 +            logout("RU is set to ready\n");
  2.1285 +            s->ru_offset = CSR_VAL(CSR_POINTER);
  2.1286 +            logout("RFD offset is at %#x\n", s->ru_offset);
  2.1287 +            break;
  2.1288 +        case RU_RESUME:
  2.1289 +            /* RU Resume */
  2.1290 +            if ( GET_RU_STATE == RU_SUSPENDED )
  2.1291 +                SET_RU_STATE(RU_READY);
  2.1292 +            logout("RU resume to ready\n");
  2.1293 +            break;
  2.1294 +        case RU_ADDR_LOAD:
  2.1295 +            /* Load RU base */
  2.1296 +            s->ru_base = CSR_VAL(CSR_POINTER);
  2.1297 +            logout("Load RU base address at %#x\n", s->ru_base);
  2.1298 +            break;
  2.1299 +        case RU_DMA_REDIRECT:
  2.1300 +            logout("RU DMA redirect not implemented\n");
  2.1301 +            break;
  2.1302 +        case RU_ABORT:
  2.1303 +            e100_interrupt(s, INT_RNR);
  2.1304 +            SET_RU_STATE(RU_IDLE);
  2.1305 +            logout("RU abort, go to idle\n");
  2.1306 +            break;
  2.1307 +        case RU_LOAD_HDS:
  2.1308 +            logout("RU load header data size(HDS) not implemented\n");
  2.1309 +        default:
  2.1310 +            break;
  2.1311 +    }
  2.1312 +}
  2.1313 +
  2.1314 +// This function will change CU's state, so CU start and
  2.1315 +// CU resume must set CU's state before it
  2.1316 +static void e100_execute_cb_list(E100State *s, int is_resume)
  2.1317 +{
  2.1318 +
  2.1319 +    struct control_block cb = {0};
  2.1320 +    uint32_t cb_addr;
  2.1321 +
  2.1322 +    if ( !is_resume )
  2.1323 +        s->cu_offset = CSR_VAL(CSR_POINTER);
  2.1324 +
  2.1325 +    /* If call from CU resume, cu_offset has been set */
  2.1326 +
  2.1327 +    while (1)
  2.1328 +    {
  2.1329 +        cb_addr = s->cu_base + s->cu_offset;
  2.1330 +        cpu_physical_memory_read(cb_addr, (uint8_t *)&cb, sizeof(cb));
  2.1331 +
  2.1332 +
  2.1333 +        switch ( cb.cmd )
  2.1334 +        {
  2.1335 +            case CBL_NOP:
  2.1336 +                /* Do nothing */
  2.1337 +                break;
  2.1338 +            case CBL_IASETUP:
  2.1339 +                cpu_physical_memory_read(cb_addr + 8, &s->macaddr[0], sizeof(s->macaddr));
  2.1340 +                e100_dump("Setup Individual Address:", &s->macaddr[0], 6);
  2.1341 +                break;
  2.1342 +            case CBL_CONFIGURE:
  2.1343 +                {
  2.1344 +                    i82557_cfg_t *cfg = &s->config;
  2.1345 +
  2.1346 +                    assert(sizeof(s->config) == 22);
  2.1347 +                    cpu_physical_memory_read(cb_addr + 8, (uint8_t *)cfg, sizeof(s->config));
  2.1348 +                    logout("Setup card configuration:"
  2.1349 +                            "\tbyte count:%d\n"
  2.1350 +                            "\tRx FIFO limit:%d\n"
  2.1351 +                            "\tTx FIFO limit:%d\n"
  2.1352 +                            "\tAdaptive interframe spacing:%d\n"
  2.1353 +                            "\tRx DMA max:%d\n"
  2.1354 +                            "\tTX DMA max:%d\n"
  2.1355 +                            "\tDMBC enable:%d\n"
  2.1356 +                            "\tLate SCB:%d\n"
  2.1357 +                            "\tTNO:%d\n"
  2.1358 +                            "\tCI:%d\n"
  2.1359 +                            "\tDiscard overrun RX:%d\n"
  2.1360 +                            "\tSave bad frame:%d\n"
  2.1361 +                            "\tDiscard short RX:%d\n"
  2.1362 +                            "\tunderrun retry:%d\n"
  2.1363 +                            "\tMII:%d\n"
  2.1364 +                            "\tNSAI:%d\n"
  2.1365 +                            "\tPreamble len:%d\n"
  2.1366 +                            "\tloopback:%d\n"
  2.1367 +                            "\tliner pro:%d\n"
  2.1368 +                            "\tPRI mode:%d\n"
  2.1369 +                            "\tinterframe spacing:%d\n"
  2.1370 +                            "\tpromiscuous:%d\n"
  2.1371 +                            "\tbroadcast dis:%d\n"
  2.1372 +                            "\tCRS CDT:%d\n"
  2.1373 +                            "\tstripping:%d\n"
  2.1374 +                            "\tpadding:%d\n"
  2.1375 +                            "\tRX crc:%d\n"
  2.1376 +                            "\tforce fdx:%d\n"
  2.1377 +                            "\tfdx enable:%d\n"
  2.1378 +                            "\tmultiple IA:%d\n"
  2.1379 +                            "\tmulticast all:%d\n",
  2.1380 +                        cfg->byte_count, cfg->rx_fifo_limit, cfg->tx_fifo_limit,
  2.1381 +                        cfg->adpt_inf_spacing, cfg->rx_dma_max_bytes, cfg->tx_dma_max_bytes,
  2.1382 +                        cfg->dmbc_en, cfg->late_scb, cfg->tno_intr, cfg->ci_intr,
  2.1383 +                        cfg->dis_overrun_rx, cfg->save_bad_frame, cfg->dis_short_rx,
  2.1384 +                        cfg->underrun_retry, cfg->mii, cfg->nsai, cfg->preamble_len,
  2.1385 +                        cfg->loopback, cfg->linear_prio, cfg->pri_mode, cfg->interframe_spacing,
  2.1386 +                        cfg->promiscuous, cfg->broadcast_dis, cfg->crs_cdt, cfg->strip,
  2.1387 +                        cfg->padding, cfg->rx_crc, cfg->force_fdx, cfg->fdx_en,
  2.1388 +                        cfg->mul_ia, cfg->mul_all);
  2.1389 +                }
  2.1390 +                break;
  2.1391 +            case CBL_MULTCAST_ADDR_SETUP:
  2.1392 +                {
  2.1393 +                    uint16_t mult_list_count = 0;
  2.1394 +                    uint16_t size = 0;
  2.1395 +
  2.1396 +                    cpu_physical_memory_read(cb_addr + 8, (uint8_t *)&mult_list_count, 2);
  2.1397 +                    mult_list_count = (mult_list_count << 2) >> 2;
  2.1398 +
  2.1399 +                    if ( !mult_list_count )
  2.1400 +                    {
  2.1401 +                        logout("Multcast disabled(multicast count=0)\n");
  2.1402 +                        s->is_multcast_enable = 0;
  2.1403 +                        memset(s->mult_list, 0x0, sizeof(s->mult_list));
  2.1404 +                        break;
  2.1405 +                    }
  2.1406 +                    size = mult_list_count > sizeof(s->mult_list) ?
  2.1407 +                        sizeof(s->mult_list) : mult_list_count;
  2.1408 +                    cpu_physical_memory_read(cb_addr + 12, &s->mult_list[0], size);
  2.1409 +
  2.1410 +                    e100_dump("Setup Multicast list: ", &s->mult_list[0], size);
  2.1411 +                    break;
  2.1412 +                }
  2.1413 +            case CBL_TRANSMIT:
  2.1414 +                {
  2.1415 +                    struct
  2.1416 +                    {
  2.1417 +                        struct control_block cb;
  2.1418 +                        tbd_t tbd;
  2.1419 +                    } __attribute__ ((packed)) tx;
  2.1420 +
  2.1421 +                    struct
  2.1422 +                    {
  2.1423 +                        uint32_t addr;
  2.1424 +                        uint16_t size;
  2.1425 +                        uint16_t is_el_set;
  2.1426 +                    } tx_buf = {0};
  2.1427 +
  2.1428 +                    uint32_t tbd_array;
  2.1429 +                    uint16_t tcb_bytes;
  2.1430 +                    uint8_t sf;
  2.1431 +                    int len = s->pkt_buf_len;
  2.1432 +
  2.1433 +                    assert( len < sizeof(s->pkt_buf));
  2.1434 +
  2.1435 +                    cpu_physical_memory_read(cb_addr, (uint8_t *)&tx, sizeof(tx));
  2.1436 +                    tbd_array = le32_to_cpu(tx.tbd.tx_desc_addr);
  2.1437 +                    tcb_bytes = le16_to_cpu(tx.tbd.tcb_bytes);
  2.1438 +                    // Indicate use what mode to transmit(simple or flexible)
  2.1439 +                    sf = tx.cb.rs3 & 0x1;
  2.1440 +
  2.1441 +                    logout("Get a TBD:\n"
  2.1442 +                            "\tTBD array address:%#x\n"
  2.1443 +                            "\tTCB byte count:%#x\n"
  2.1444 +                            "\tEOF:%#x\n"
  2.1445 +                            "\tTransmit Threshold:%#x\n"
  2.1446 +                            "\tTBD number:%#x\n"
  2.1447 +                            "\tUse %s mode to send frame\n",
  2.1448 +                            tbd_array, tcb_bytes, tx.tbd.eof,
  2.1449 +                            tx.tbd.tx_threshold, tx.tbd.tbd_num,
  2.1450 +                            sf ? "Flexible" : "Simple");
  2.1451 +
  2.1452 +                    if ( !sf || tbd_array == (uint32_t)-1 )
  2.1453 +                    {
  2.1454 +                        /* Simple mode */
  2.1455 +
  2.1456 +                        /* For simple mode, TCB bytes should not be zero.
  2.1457 +                         * But we still check here for safety
  2.1458 +                         */
  2.1459 +                        if ( !tcb_bytes || tcb_bytes > sizeof(s->pkt_buf) )
  2.1460 +                            break;
  2.1461 +
  2.1462 +                        cpu_physical_memory_read(cb_addr+16, &s->pkt_buf[0], tcb_bytes);
  2.1463 +                        len = tcb_bytes;
  2.1464 +                        logout("simple mode(size=%d)\n", len);
  2.1465 +
  2.1466 +                    }
  2.1467 +                    else
  2.1468 +                    {
  2.1469 +                        /* Flexible mode */
  2.1470 +
  2.1471 +                        /* For flexible mode, TBD num should not be zero.
  2.1472 +                         * But we still check here for safety
  2.1473 +                         */
  2.1474 +                        if ( !tx.tbd.tbd_num )
  2.1475 +                            break;
  2.1476 +
  2.1477 +                        // I82557 don't support extend TCB
  2.1478 +                        if ( s->device == i82557C || s->device == i82557B )
  2.1479 +                        {
  2.1480 +                            /* Standard TCB mode */
  2.1481 +
  2.1482 +                            int i;
  2.1483 +
  2.1484 +                            for ( i=0; i<tx.tbd.tbd_num; i++ )
  2.1485 +                            {
  2.1486 +
  2.1487 +                                cpu_physical_memory_read(tbd_array, (uint8_t *)&tx_buf,
  2.1488 +                                        sizeof(tx_buf));
  2.1489 +                                tx_buf.is_el_set &= 0x1;
  2.1490 +                                tx_buf.size &= 0x7fff;
  2.1491 +                                tbd_array += 8;
  2.1492 +
  2.1493 +                                if ( tx_buf.size > sizeof(s->pkt_buf) - len )
  2.1494 +                                {
  2.1495 +                                    logout("Warning: Get a too big TBD, ignore it"
  2.1496 +                                            "(buf addr %#x, size %d, el:%#x)\n",
  2.1497 +                                            tx_buf.addr, tx_buf.size, tx_buf.is_el_set);
  2.1498 +                                    continue;
  2.1499 +                                }
  2.1500 +
  2.1501 +                                cpu_physical_memory_read(tx_buf.addr, &s->pkt_buf[len],
  2.1502 +                                        tx_buf.size);
  2.1503 +
  2.1504 +                                logout("TBD (standard mode): buf addr %#x, size %d, el:%#x\n",
  2.1505 +                                        tx_buf.addr, tx_buf.size, tx_buf.is_el_set);
  2.1506 +                                len += tx_buf.size;
  2.1507 +
  2.1508 +                                if ( tx_buf.is_el_set )
  2.1509 +                                    break;
  2.1510 +                            }
  2.1511 +
  2.1512 +                        }
  2.1513 +                        //FIXME: Extend mode is not be tested
  2.1514 +                        else
  2.1515 +                        {
  2.1516 +                            /* Extend TCB mode */
  2.1517 +
  2.1518 +                            /* A strandard TCB followed by two TBDs */
  2.1519 +                            uint32_t tbd_addr = cb_addr+16;
  2.1520 +                            int i = 0;
  2.1521 +
  2.1522 +
  2.1523 +                            for ( ; i<2 && i<tx.tbd.tbd_num; i++ )
  2.1524 +                            {
  2.1525 +
  2.1526 +                                cpu_physical_memory_read(tbd_array, (uint8_t *)&tx_buf,
  2.1527 +                                        sizeof(tx_buf));
  2.1528 +                                tx_buf.is_el_set &= 0x1;
  2.1529 +                                tbd_addr += 8;
  2.1530 +
  2.1531 +                                /* From Intel's spec, size of TBD equal to zero
  2.1532 +                                 * has same effect with EL bit set
  2.1533 +                                 */
  2.1534 +                                if ( tx_buf.size == 0 )
  2.1535 +                                {
  2.1536 +                                    tx_buf.is_el_set = 1;
  2.1537 +                                    break;
  2.1538 +                                }
  2.1539 +
  2.1540 +                                if ( tx_buf.size + len > sizeof(s->pkt_buf) )
  2.1541 +                                {
  2.1542 +                                    logout("TX frame is too large, discarding it"
  2.1543 +                                            "(buf addr=%#x, size=%#x)\n", tx_buf.addr,
  2.1544 +                                            tx_buf.size);
  2.1545 +                                    //continue;
  2.1546 +                                    break;
  2.1547 +                                }
  2.1548 +
  2.1549 +                                logout("TBD (extended mode): buf addr %#08x, size %#04x, el:%#x\n",
  2.1550 +                                        tx_buf.addr, tx_buf.size, tx_buf.is_el_set);
  2.1551 +                                cpu_physical_memory_read(tx_buf.addr, &s->pkt_buf[len],
  2.1552 +                                        tx_buf.size);
  2.1553 +
  2.1554 +                                len += tx_buf.size;
  2.1555 +
  2.1556 +                                if ( tx_buf.is_el_set )
  2.1557 +                                    break;
  2.1558 +                            }
  2.1559 +
  2.1560 +                            /* In extend TCB mode, TDB array point to the thrid TBD
  2.1561 +                             * if it is not NULL(0xffffffff) and EL bit of before
  2.1562 +                             * two TBDs is not set
  2.1563 +                             */
  2.1564 +                            if ( tbd_array != (uint32_t)-1 && !tx_buf.is_el_set )
  2.1565 +                            {
  2.1566 +                                tbd_addr = tbd_array;
  2.1567 +
  2.1568 +                                /* TBD number includes first two TBDs, so don't
  2.1569 +                                 * initialize i here
  2.1570 +                                 */
  2.1571 +                                for ( ; i<tx.tbd.tbd_num; i++ )
  2.1572 +                                {
  2.1573 +                                    cpu_physical_memory_read(tbd_addr, (uint8_t *)&tx_buf,
  2.1574 +                                            sizeof(tx_buf));
  2.1575 +                                    tx_buf.is_el_set &= 0x1;
  2.1576 +                                    tbd_addr += 8;
  2.1577 +
  2.1578 +                                    cpu_physical_memory_read(tx_buf.addr, &s->pkt_buf[len],
  2.1579 +                                            tx_buf.size);
  2.1580 +                                    logout("TBD (extended mode): buf addr 0x%#08x, size 0x%#04x\n",
  2.1581 +                                            tx_buf.addr, tx_buf.size);
  2.1582 +
  2.1583 +                                    len += tx_buf.size;
  2.1584 +
  2.1585 +                                    if ( tx_buf.is_el_set )
  2.1586 +                                        break;
  2.1587 +                                }
  2.1588 +                            }
  2.1589 +                        }
  2.1590 +                    }
  2.1591 +
  2.1592 +
  2.1593 +                    s->pkt_buf_len = len;
  2.1594 +
  2.1595 +/* Below codes are used for Threshold. But with these logic, network of guest
  2.1596 + * getting bad performance. So I comment it and leave codes here to hope anyone
  2.1597 + * fix it
  2.1598 + */
  2.1599 +#if 0
  2.1600 +                    /* If threshold is set, only send packet when threshold
  2.1601 +                     * bytes are read
  2.1602 +                     */
  2.1603 +                    if ( tx.tbd.tx_threshold && s->pkt_buf_len < tx.tbd.tx_threshold * 8 )
  2.1604 +                    {
  2.1605 +                        logout("Current data length in FIFO buffer:%d\n", s->pkt_buf_len);
  2.1606 +                        break;
  2.1607 +                    }
  2.1608 +#endif
  2.1609 +
  2.1610 +                    if ( s->pkt_buf_len )
  2.1611 +                    {
  2.1612 +                        qemu_send_packet(s->vc, s->pkt_buf, s->pkt_buf_len);
  2.1613 +                        s->statistics.tx_good_frames ++;
  2.1614 +                        logout("Send out frame successful(size=%d,"
  2.1615 +                                "already sent %d frames)\n", s->pkt_buf_len,
  2.1616 +                                s->statistics.tx_good_frames);
  2.1617 +                        s->pkt_buf_len = 0;
  2.1618 +                    }
  2.1619 +
  2.1620 +                    e100_dump("Dest addr:", (uint8_t *)s->pkt_buf, 6);
  2.1621 +                    e100_dump("Src addr:", (uint8_t *)(s->pkt_buf+6), 6);
  2.1622 +                    e100_dump("type:", (uint8_t *)(s->pkt_buf+8), 2);
  2.1623 +
  2.1624 +                    break;
  2.1625 +                }
  2.1626 +            case CBL_LOAD_MICROCODE:
  2.1627 +#ifdef DEBUG_E100
  2.1628 +                {
  2.1629 +                    /* Don't support load marco code, just dump it */
  2.1630 +                    #define MICRO_CODE_LEN 256
  2.1631 +                    uint8_t micro_code[MICRO_CODE_LEN] = {0};
  2.1632 +                    cpu_physical_memory_read(cb_addr+8, micro_code, MICRO_CODE_LEN);
  2.1633 +                    e100_dump("Load micro code:", micro_code, MICRO_CODE_LEN);
  2.1634 +                }
  2.1635 +#endif
  2.1636 +                break;
  2.1637 +            case CBL_DUMP:
  2.1638 +                logout("Control block dump\n");
  2.1639 +                break;
  2.1640 +            case CBL_DIAGNOSE:
  2.1641 +                logout("Control block diagnose\n");
  2.1642 +                break;
  2.1643 +            default:
  2.1644 +                logout("Unknown Control block command(val=%#x)\n", cb.cmd);
  2.1645 +                break;
  2.1646 +        }
  2.1647 +
  2.1648 +        /* Now, we finished executing a command, update status of CB.
  2.1649 +         * We always success
  2.1650 +         */
  2.1651 +        cb.c = 1;
  2.1652 +        cb.ok = 1;
  2.1653 +        // Only update C bit and OK bit field in TCB
  2.1654 +        cpu_physical_memory_write(cb_addr, (uint8_t *)&cb, 2);
  2.1655 +
  2.1656 +        logout("Finished a command from CB list:\n"
  2.1657 +                "\tok:%d\n"
  2.1658 +                "\tc:%d\n"
  2.1659 +                "\tcommand name:%s(cmd=%#x)\n"
  2.1660 +                "\ti:%d\n"
  2.1661 +                "\ts:%d\n"
  2.1662 +                "\tel:%d\n"
  2.1663 +                "\tlink address:%#x\n",
  2.1664 +                cb.ok, cb.c, CB_CMD_NAME(cb.cmd), cb.cmd,
  2.1665 +                cb.i, cb.s, cb.el, cb.link_addr);
  2.1666 +
  2.1667 +        if ( cb.i )
  2.1668 +            e100_interrupt(s, (uint16_t)INT_CX_TNO);
  2.1669 +
  2.1670 +        // Suspend CU
  2.1671 +        if ( cb.s )
  2.1672 +        {
  2.1673 +            logout("CU go to suspend\n");
  2.1674 +            SET_CU_STATE(CU_SUSPENDED);
  2.1675 +            s->cu_next = cb.link_addr; // Save it for go on executing when resume
  2.1676 +
  2.1677 +            // Trigger CNA interrupt only when CNA mode is configured
  2.1678 +            if ( !(s->config.ci_intr) && cb.i )
  2.1679 +                e100_interrupt(s, (uint16_t)INT_CNA);
  2.1680 +
  2.1681 +            return;
  2.1682 +        }
  2.1683 +
  2.1684 +        // This is last command in CB list, CU go back to IDLE
  2.1685 +        if ( cb.el )
  2.1686 +        {
  2.1687 +            logout("Command block list is empty, CU go to idle\n");
  2.1688 +            SET_CU_STATE(CU_IDLE);
  2.1689 +            /* Either in CNA mode or CI mode, interrupt need be triggered
  2.1690 +             * when CU go to idle.
  2.1691 +             */
  2.1692 +            if ( cb.i )
  2.1693 +                e100_interrupt(s, (uint16_t)INT_CNA);
  2.1694 +
  2.1695 +            return;
  2.1696 +        }
  2.1697 +
  2.1698 +        s->cu_offset = le32_to_cpu(cb.link_addr); // get next CB offset
  2.1699 +    }
  2.1700 +}
  2.1701 +
  2.1702 +static void dump_statistics(E100State * s, uint32_t complete_word)
  2.1703 +{
  2.1704 +    /* Dump statistical data. Most data is never changed by the emulation
  2.1705 +     * and always 0.
  2.1706 +     */
  2.1707 +    s->statistics.complete_word = complete_word;
  2.1708 +    cpu_physical_memory_write(s->statsaddr, (uint8_t *)&s->statistics, sizeof(s->statistics));
  2.1709 +
  2.1710 +}
  2.1711 +
  2.1712 +static void e100_cu_command(E100State *s, uint8_t val)
  2.1713 +{
  2.1714 +
  2.1715 +    switch ( val )
  2.1716 +    {
  2.1717 +        case CU_NOP:
  2.1718 +            /* Will not be here */
  2.1719 +            break;
  2.1720 +        case CU_START:
  2.1721 +            /* This strictly follow Intel's spec */
  2.1722 +            if ( GET_CU_STATE != CU_IDLE && GET_CU_STATE != CU_SUSPENDED )
  2.1723 +            {
  2.1724 +                logout("Illegal CU start command. Device is not idle or suspend\n");
  2.1725 +                return;
  2.1726 +            }
  2.1727 +
  2.1728 +            SET_CU_STATE(CU_LPQ_ACTIVE);
  2.1729 +            logout("CU start\n");
  2.1730 +
  2.1731 +            e100_execute_cb_list(s, 0);
  2.1732 +            break;
  2.1733 +        case CU_RESUME:
  2.1734 +            {
  2.1735 +                uint32_t previous_cb = s->cu_base + s->cu_offset;
  2.1736 +                struct control_block cb;
  2.1737 +
  2.1738 +                /* Resume from suspend */
  2.1739 +
  2.1740 +                /* FIXME:From Intel's spec, CU resume from idle is
  2.1741 +                 * forbidden, but e100 drive in linux
  2.1742 +                 * indeed do this.
  2.1743 +                 */
  2.1744 +                if ( GET_CU_STATE == CU_IDLE )
  2.1745 +                {
  2.1746 +                    logout("Illegal resume form IDLE\n");
  2.1747 +                }
  2.1748 +
  2.1749 +                cpu_physical_memory_read(previous_cb, (uint8_t *)&cb,
  2.1750 +                                        sizeof(cb));
  2.1751 +
  2.1752 +                //FIXME: Need any speical handle when CU is active ?
  2.1753 +
  2.1754 +                /* Driver must clean S bit in previous CB when
  2.1755 +                 * it issue CU resume command
  2.1756 +                 */
  2.1757 +                if ( cb.s )
  2.1758 +                {
  2.1759 +                    logout("CU still in suspend\n");
  2.1760 +                    break;
  2.1761 +                }
  2.1762 +
  2.1763 +                SET_CU_STATE(CU_LPQ_ACTIVE);
  2.1764 +                if ( cb.el )
  2.1765 +                {
  2.1766 +                    logout("CB list is empty, CU just go to active\n");
  2.1767 +                    break;
  2.1768 +                }
  2.1769 +
  2.1770 +                // Continue next command
  2.1771 +                s->cu_offset = s->cu_next;
  2.1772 +
  2.1773 +                e100_execute_cb_list(s, 1);
  2.1774 +
  2.1775 +                logout("CU resume\n");
  2.1776 +            }
  2.1777 +            break;
  2.1778 +        case CU_STATSADDR:
  2.1779 +            /* Load dump counters address */
  2.1780 +            s->statsaddr = CSR_VAL(CSR_POINTER);
  2.1781 +            logout("Load Stats address at %#x\n", s->statsaddr);
  2.1782 +            break;
  2.1783 +        case CU_SHOWSTATS:
  2.1784 +            /* Dump statistical counters */
  2.1785 +            dump_statistics(s, 0xa005);
  2.1786 +            logout("Execute dump statistics\n");
  2.1787 +            break;
  2.1788 +        case CU_CMD_BASE:
  2.1789 +            /* Load CU base */
  2.1790 +            s->cu_base = CSR_VAL(CSR_POINTER);
  2.1791 +            logout("Load CU base at %x\n", s->cu_base);
  2.1792 +            break;
  2.1793 +        case CU_DUMPSTATS:
  2.1794 +            /* Dump statistical counters and reset counters. */
  2.1795 +            dump_statistics(s, 0xa007);
  2.1796 +            memset(&s->statistics, 0x0, sizeof(s->statistics));
  2.1797 +            logout("Execute dump and reset statistics\n");
  2.1798 +            break;
  2.1799 +        case CU_S_RESUME:
  2.1800 +            /* CU static resume */
  2.1801 +            logout("CU static resume is not implemented\n");
  2.1802 +            break;
  2.1803 +        default:
  2.1804 +            logout("Unknown CU command(val=%#x)\n", val);
  2.1805 +            break;
  2.1806 +    }
  2.1807 +
  2.1808 +}
  2.1809 +
  2.1810 +static void scb_cmd_func(E100State *s, uint16_t val, int dir)
  2.1811 +{
  2.1812 +    /* ignore NOP operation */
  2.1813 +    if ( val & 0x0f )
  2.1814 +    {
  2.1815 +        e100_ru_command(s, val & 0x0f);
  2.1816 +        CSR(CSR_CMD, ru_cmd) = 0;
  2.1817 +    }
  2.1818 +    else if ( val & 0xf0 )
  2.1819 +    {
  2.1820 +        e100_cu_command(s, val & 0xf0);
  2.1821 +        CSR(CSR_CMD, cu_cmd) = 0;
  2.1822 +    }
  2.1823 +
  2.1824 +}
  2.1825 +
  2.1826 +enum
  2.1827 +{
  2.1828 +    WRITEB,
  2.1829 +    WRITEW,
  2.1830 +    WRITEL,
  2.1831 +    OP_IS_READ,
  2.1832 +} WRITE_BYTES;
  2.1833 +
  2.1834 +/* Driver may issue a command by writting one 32bit-entry,
  2.1835 + * two 16bit-entries or four 8bit-entries. In late two case, we
  2.1836 + * must wait until driver finish writting to the highest byte. The parameter
  2.1837 + * 'bytes' means write action of driver(writeb, wirtew, wirtel)
  2.1838 + */
  2.1839 +static void e100_execute(E100State *s, uint32_t addr_offset,
  2.1840 +        uint32_t val, int dir, int bytes)
  2.1841 +{
  2.1842 +
  2.1843 +    switch ( addr_offset )
  2.1844 +    {
  2.1845 +        case SCB_STATUS:
  2.1846 +            if ( bytes == WRITEB )
  2.1847 +                break;
  2.1848 +        case SCB_ACK:
  2.1849 +            if ( dir == OP_WRITE )
  2.1850 +            {
  2.1851 +                uint8_t _val = 0;
  2.1852 +                if ( bytes == WRITEB )
  2.1853 +                    _val = (uint8_t)val;
  2.1854 +                else if ( bytes == WRITEW )
  2.1855 +                    _val = ((uint16_t)val) >> 8;
  2.1856 +                else if ( bytes == WRITEL)
  2.1857 +                {
  2.1858 +                    // This should not be happen
  2.1859 +                    _val = ((uint16_t)val) >> 8;
  2.1860 +                    logout("WARNNING: Drvier write 4 bytes to CSR register at offset %d,"
  2.1861 +                           "emulator may do things wrong!!!\n", addr_offset);
  2.1862 +                }
  2.1863 +
  2.1864 +                e100_interrupt_ack(s, _val);
  2.1865 +            }
  2.1866 +            break;
  2.1867 +        case SCB_CMD:
  2.1868 +            if ( dir == OP_WRITE )
  2.1869 +                scb_cmd_func(s, val, dir);
  2.1870 +
  2.1871 +/* I don't know whether there is any driver writes command words and
  2.1872 + * interrupt mask at same time by two bytes. This is not a regular operation.
  2.1873 + * but if we meet the case, below codes could copy with it. As far
  2.1874 + * as I know. windows's and linux's driver don't do this thing.
  2.1875 + */
  2.1876 +#if 0
  2.1877 +            if ( bytes == WRITEW && (val&0xff00) != 0 )
  2.1878 +                ;
  2.1879 +            else
  2.1880 +                break;
  2.1881 +#endif
  2.1882 +            break;
  2.1883 +        case SCB_INTERRUPT_MASK:
  2.1884 +            if ( dir == OP_WRITE )
  2.1885 +            {
  2.1886 +                uint8_t _val = 0;
  2.1887 +                if ( bytes == WRITEB )
  2.1888 +                    _val = (uint8_t)val;
  2.1889 +                else if ( bytes == WRITEW )
  2.1890 +                    _val = (val & 0xff00) >> 8;
  2.1891 +                else
  2.1892 +                    logout("WARNNING: Drvier write 4 bytes to CSR register at offset %d,"
  2.1893 +                           "emulator may do things wrong!!!\n", addr_offset);
  2.1894 +
  2.1895 +                // Driver generates a software interrupt
  2.1896 +                if ( _val & BIT(1) )
  2.1897 +                    e100_interrupt(s, INT_SWI);
  2.1898 +            }
  2.1899 +            break;
  2.1900 +        case SCB_PORT ... SCB_PORT + 3:
  2.1901 +            if ( dir == OP_WRITE )
  2.1902 +            {
  2.1903 +                // Waitting for driver write to the highest byte
  2.1904 +                if ( (bytes == WRITEB && addr_offset != SCB_PORT + 3) ||
  2.1905 +                     (bytes == WRITEW && addr_offset != SCB_PORT + 2) )
  2.1906 +                    break;
  2.1907 +
  2.1908 +                scb_port_func(s, CSR_VAL(CSR_PORT), dir);
  2.1909 +            }
  2.1910 +            break;
  2.1911 +        case SCB_MDI ... SCB_MDI + 3:
  2.1912 +            if ( dir == OP_WRITE )
  2.1913 +            {
  2.1914 +                // Waitting for driver write to the highest byte
  2.1915 +                if ( (bytes == WRITEB && addr_offset != SCB_MDI + 3) ||
  2.1916 +                     (bytes == WRITEW && addr_offset != SCB_MDI + 2) )
  2.1917 +                    break;
  2.1918 +            }
  2.1919 +
  2.1920 +            scb_mdi_func(s, CSR_VAL(CSR_MDI), dir);
  2.1921 +            break;
  2.1922 +        case SCB_EEPROM:
  2.1923 +            if ( dir == OP_WRITE )
  2.1924 +                scb_eeprom_func(s, val, dir);
  2.1925 +            // Nothing need do when driver read EEPROM registers of CSR
  2.1926 +            break;
  2.1927 +        case SCB_POINTER:
  2.1928 +            break;
  2.1929 +        default:
  2.1930 +            logout("Driver operate on CSR reg(offset=%#x,dir=%s,val=%#x)\n",
  2.1931 +                    addr_offset, dir==OP_WRITE?"write":"read", val);
  2.1932 +    }
  2.1933 +
  2.1934 +}
  2.1935 +
  2.1936 +/* MMIO access functions */
  2.1937 +static uint8_t e100_read1(E100State * s, uint32_t addr_offset)
  2.1938 +{
  2.1939 +    uint8_t val = -1;
  2.1940 +
  2.1941 +    if ( addr_offset + sizeof(val) >= sizeof(s->pci_mem.mem) )
  2.1942 +    {
  2.1943 +        logout("Invaild read, beyond memory boundary(addr:%#x)\n", addr_offset
  2.1944 +                + s->region_base_addr[CSR_MEMORY_BASE]);
  2.1945 +        return val;
  2.1946 +    }
  2.1947 +
  2.1948 +
  2.1949 +    e100_execute(s, addr_offset, val, OP_READ, OP_IS_READ);
  2.1950 +    val = CSR_READ(addr_offset, uint8_t);
  2.1951 +    logout("READ1: Register name = %s, addr_offset = %#x, val=%#x\n", SCBNAME(addr_offset), addr_offset, val);
  2.1952 +
  2.1953 +    return val;
  2.1954 +}
  2.1955 +
  2.1956 +static uint16_t e100_read2(E100State * s, uint32_t addr_offset)
  2.1957 +{
  2.1958 +    uint16_t val = -1;
  2.1959 +
  2.1960 +    if ( addr_offset + sizeof(val) >= sizeof(s->pci_mem.mem) )
  2.1961 +    {
  2.1962 +        logout("Invaild read, beyond memory boundary(addr:%#x)\n", addr_offset 
  2.1963 +                + s->region_base_addr[CSR_MEMORY_BASE]);
  2.1964 +        return val;
  2.1965 +    }
  2.1966 +
  2.1967 +    e100_execute(s, addr_offset, val, OP_READ, OP_IS_READ);
  2.1968 +    val = CSR_READ(addr_offset, uint16_t);
  2.1969 +    logout("READ2: Register name = %s, addr_offset = %#x, val=%#x\n", SCBNAME(addr_offset), addr_offset, val);
  2.1970 +
  2.1971 +    return val;
  2.1972 +
  2.1973 +}
  2.1974 +
  2.1975 +static uint32_t e100_read4(E100State * s, uint32_t addr_offset)
  2.1976 +{
  2.1977 +    uint32_t val = -1;
  2.1978 +
  2.1979 +    if ( addr_offset + sizeof(val) >= sizeof(s->pci_mem.mem) )
  2.1980 +    {
  2.1981 +        logout("Invaild read, beyond memory boundary(addr:%#x)\n", addr_offset 
  2.1982 +                + s->region_base_addr[CSR_MEMORY_BASE]);
  2.1983 +        return val;
  2.1984 +    }
  2.1985 +
  2.1986 +    e100_execute(s, addr_offset, val, OP_READ, OP_IS_READ);
  2.1987 +    val = CSR_READ(addr_offset, uint32_t);
  2.1988 +    logout("READ4: Register name = %s, addr_offset = %#x, val=%#x\n", SCBNAME(addr_offset), addr_offset, val);
  2.1989 +
  2.1990 +    return val;
  2.1991 +
  2.1992 +}
  2.1993 +
  2.1994 +static uint32_t pci_mmio_readb(void *opaque, target_phys_addr_t addr)
  2.1995 +{
  2.1996 +    E100State *s = opaque;
  2.1997 +    addr -= s->region_base_addr[CSR_MEMORY_BASE];
  2.1998 +    return e100_read1(s, addr);
  2.1999 +}
  2.2000 +
  2.2001 +static uint32_t pci_mmio_readw(void *opaque, target_phys_addr_t addr)
  2.2002 +{
  2.2003 +    E100State *s = opaque;
  2.2004 +    addr -= s->region_base_addr[CSR_MEMORY_BASE];
  2.2005 +    return e100_read2(s, addr);
  2.2006 +}
  2.2007 +
  2.2008 +static uint32_t pci_mmio_readl(void *opaque, target_phys_addr_t addr)
  2.2009 +{
  2.2010 +    E100State *s = opaque;
  2.2011 +    addr -= s->region_base_addr[CSR_MEMORY_BASE];
  2.2012 +    return e100_read4(s, addr);
  2.2013 +}
  2.2014 +
  2.2015 +static CPUReadMemoryFunc *pci_mmio_read[] = {
  2.2016 +    pci_mmio_readb,
  2.2017 +    pci_mmio_readw,
  2.2018 +    pci_mmio_readl
  2.2019 +};
  2.2020 +
  2.2021 +static void e100_write1(E100State * s, uint32_t addr_offset, uint8_t val)
  2.2022 +{
  2.2023 +    if ( addr_offset + sizeof(val) >= sizeof(s->pci_mem.mem) )
  2.2024 +    {
  2.2025 +        logout("Invaild write, beyond memory boundary(addr = %#x, val = %#x\n", addr_offset
  2.2026 +                + s->region_base_addr[CSR_MEMORY_BASE], val);
  2.2027 +        return;
  2.2028 +    }
  2.2029 +
  2.2030 +    // SCB stauts is read-only word, can not be directly write
  2.2031 +    if ( addr_offset == SCB_STATUS )
  2.2032 +    {
  2.2033 +        return;
  2.2034 +    }
  2.2035 +    // EEDO bit of eeprom register is read-only, can not be written;
  2.2036 +    else if ( addr_offset == SCB_EEPROM )
  2.2037 +    {
  2.2038 +        int eedo = BIT(3) & CSR_VAL(CSR_EEPROM);
  2.2039 +        CSR_WRITE(addr_offset, val, uint8_t);
  2.2040 +        CSR(CSR_EEPROM, eedo) = !!(eedo & EEPROM_DO);
  2.2041 +
  2.2042 +        logout("WRITE1: Register name = %s, addr_offset = %#x, val = %#x\n", SCBNAME(addr_offset),addr_offset, (uint8_t)CSR_VAL(CSR_EEPROM));
  2.2043 +        return;
  2.2044 +    }
  2.2045 +    else
  2.2046 +    {
  2.2047 +        CSR_WRITE(addr_offset, val, uint8_t);
  2.2048 +    }
  2.2049 +
  2.2050 +    logout("WRITE1: Register name = %s, addr_offset = %#x, val = %#x\n", SCBNAME(addr_offset),addr_offset, val);
  2.2051 +    return;
  2.2052 +}
  2.2053 +
  2.2054 +static void e100_write2(E100State * s, uint32_t addr_offset, uint16_t val)
  2.2055 +{
  2.2056 +    if ( addr_offset + sizeof(val) >= sizeof(s->pci_mem.mem) )
  2.2057 +    {
  2.2058 +        logout("Invaild write, beyond memory boundary(addr = %#x, val = %#x\n", addr_offset
  2.2059 +                + s->region_base_addr[CSR_MEMORY_BASE], val);
  2.2060 +        return;
  2.2061 +    }
  2.2062 +
  2.2063 +    // SCB stauts is readonly word, can not be directly write
  2.2064 +    if ( addr_offset == SCB_STATUS )
  2.2065 +    {
  2.2066 +        uint8_t __val = val >> 8;
  2.2067 +        CSR_WRITE(addr_offset+1, __val, uint8_t);
  2.2068 +    }
  2.2069 +    // EEDO bit of eeprom register is read-only, can not be written;
  2.2070 +    else if ( addr_offset == SCB_EEPROM )
  2.2071 +    {
  2.2072 +        int eedo = BIT(3) & CSR_VAL(CSR_EEPROM);
  2.2073 +        CSR_WRITE(addr_offset, val, uint16_t);
  2.2074 +        CSR(CSR_EEPROM, eedo) = !!(eedo & EEPROM_DO);
  2.2075 +
  2.2076 +        logout("WRITE1: Register name = %s, addr_offset = %#x, val = %#x\n", SCBNAME(addr_offset),addr_offset, CSR_VAL(CSR_EEPROM));
  2.2077 +        return;
  2.2078 +    }
  2.2079 +    else
  2.2080 +    {
  2.2081 +        CSR_WRITE(addr_offset, val, uint16_t);
  2.2082 +    }
  2.2083 +
  2.2084 +    logout("WRITE2: Register name = %s, addr_offset = %#x, val = %#x\n", SCBNAME(addr_offset),addr_offset, val);
  2.2085 +    return;
  2.2086 +}
  2.2087 +
  2.2088 +static void e100_write4(E100State * s, uint32_t addr_offset, uint32_t val)
  2.2089 +{
  2.2090 +    if ( addr_offset + sizeof(val) >= sizeof(s->pci_mem.mem) )
  2.2091 +    {
  2.2092 +        logout("Invaild write, beyond memory boundary(addr = %#x, val = %#x\n", addr_offset 
  2.2093 +                + s->region_base_addr[CSR_MEMORY_BASE], val);
  2.2094 +        return;
  2.2095 +    }
  2.2096 +
  2.2097 +    // SCB stauts is readonly word, can not be directly write
  2.2098 +    if ( addr_offset == SCB_STATUS )
  2.2099 +    {
  2.2100 +        uint8_t __val[4] = {0};
  2.2101 +
  2.2102 +        //FIXME: any un-aligned reference ?
  2.2103 +        *(uint32_t *)&__val = val;
  2.2104 +
  2.2105 +        CSR_WRITE(addr_offset+1, __val[1], uint8_t);
  2.2106 +        CSR_WRITE(addr_offset+2, __val[2], uint8_t);
  2.2107 +        CSR_WRITE(addr_offset+3, __val[3], uint8_t);
  2.2108 +    }
  2.2109 +    /* No write4 opertaion on EEPROM register */
  2.2110 +    else
  2.2111 +    {
  2.2112 +        CSR_WRITE(addr_offset, val, uint32_t);
  2.2113 +    }
  2.2114 +
  2.2115 +    logout("WRITE4: Register name = %s, addr_offset = %#x, val = %#x\n", SCBNAME(addr_offset),addr_offset, val);
  2.2116 +    return;
  2.2117 +}
  2.2118 +
  2.2119 +static void pci_mmio_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
  2.2120 +{
  2.2121 +    E100State *s = opaque;
  2.2122 +    addr -= s->region_base_addr[CSR_MEMORY_BASE];
  2.2123 +    e100_write1(s, addr, val);
  2.2124 +    e100_execute(s, addr, val, OP_WRITE, WRITEB);
  2.2125 +}
  2.2126 +
  2.2127 +static void pci_mmio_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
  2.2128 +{
  2.2129 +    E100State *s = opaque;
  2.2130 +    addr -= s->region_base_addr[CSR_MEMORY_BASE];
  2.2131 +    e100_write2(s, addr, val);
  2.2132 +    e100_execute(s, addr, val, OP_WRITE, WRITEW);
  2.2133 +}
  2.2134 +
  2.2135 +static void pci_mmio_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
  2.2136 +{
  2.2137 +    E100State *s = opaque;
  2.2138 +    addr -= s->region_base_addr[CSR_MEMORY_BASE];
  2.2139 +    e100_write4(s, addr, val);
  2.2140 +    (void)e100_execute(s, addr, val, OP_WRITE, WRITEL);
  2.2141 +}
  2.2142 +
  2.2143 +static CPUWriteMemoryFunc *pci_mmio_write[] = {
  2.2144 +    pci_mmio_writeb,
  2.2145 +    pci_mmio_writew,
  2.2146 +    pci_mmio_writel
  2.2147 +};
  2.2148 +
  2.2149 +static void pci_mmio_map(PCIDevice * pci_dev, int region_num,
  2.2150 +                         uint32_t addr, uint32_t size, int type)
  2.2151 +{
  2.2152 +    PCIE100State *d = (PCIE100State *) pci_dev;
  2.2153 +
  2.2154 +    logout("region %d, addr=0x%08x, size=0x%08x, type=%d\n",
  2.2155 +           region_num, addr, size, type);
  2.2156 +
  2.2157 +    if ( region_num == CSR_MEMORY_BASE ) {
  2.2158 +        /* Map control / status registers. */
  2.2159 +        cpu_register_physical_memory(addr, size, d->e100.mmio_index);
  2.2160 +        d->e100.region_base_addr[region_num] = addr;
  2.2161 +    }
  2.2162 +}
  2.2163 +
  2.2164 +/* IO access functions */
  2.2165 +static void ioport_write1(void *opaque, uint32_t addr, uint32_t val)
  2.2166 +{
  2.2167 +    E100State *s = opaque;
  2.2168 +    addr -= s->region_base_addr[CSR_IO_BASE];
  2.2169 +    e100_write1(s, addr, val);
  2.2170 +    (void)e100_execute(s, addr, (uint32_t)val, OP_WRITE, WRITEB);
  2.2171 +}
  2.2172 +
  2.2173 +static void ioport_write2(void *opaque, uint32_t addr, uint32_t val)
  2.2174 +{
  2.2175 +    E100State *s = opaque;
  2.2176 +    addr -= s->region_base_addr[CSR_IO_BASE];
  2.2177 +    e100_write2(s, addr, val);
  2.2178 +    (void)e100_execute(s, addr, (uint32_t)val, OP_WRITE, WRITEW);
  2.2179 +}
  2.2180 +
  2.2181 +static void ioport_write4(void *opaque, uint32_t addr, uint32_t val)
  2.2182 +{
  2.2183 +    E100State *s = opaque;
  2.2184 +    addr -= s->region_base_addr[CSR_IO_BASE];
  2.2185 +    e100_write4(s, addr, val);
  2.2186 +    (void)e100_execute(s, addr, (uint32_t)val, OP_WRITE, WRITEL);
  2.2187 +}
  2.2188 +
  2.2189 +static uint32_t ioport_read1(void *opaque, uint32_t addr)
  2.2190 +{
  2.2191 +    E100State *s = opaque;
  2.2192 +    addr -= s->region_base_addr[CSR_IO_BASE];
  2.2193 +    return e100_read1(s, addr);
  2.2194 +}
  2.2195 +
  2.2196 +static uint32_t ioport_read2(void *opaque, uint32_t addr)
  2.2197 +{
  2.2198 +    E100State *s = opaque;
  2.2199 +    addr -= s->region_base_addr[CSR_IO_BASE];
  2.2200 +    return e100_read2(s, addr);
  2.2201 +}
  2.2202 +
  2.2203 +static uint32_t ioport_read4(void *opaque, uint32_t addr)
  2.2204 +{
  2.2205 +    E100State *s = opaque;
  2.2206 +    addr -= s->region_base_addr[CSR_IO_BASE];
  2.2207 +    return e100_read4(s, addr);
  2.2208 +}
  2.2209 +
  2.2210 +static void pci_ioport_map(PCIDevice * pci_dev, int region_num,
  2.2211 +                    uint32_t addr, uint32_t size, int type)
  2.2212 +{
  2.2213 +    PCIE100State *d = (PCIE100State *) pci_dev;
  2.2214 +    E100State *s = &d->e100;
  2.2215 +
  2.2216 +    logout("region %d, addr=0x%08x, size=0x%08x, type=%d\n",
  2.2217 +           region_num, addr, size, type);
  2.2218 +
  2.2219 +    if ( region_num != 1 )
  2.2220 +    {
  2.2221 +        logout("Invaid region number!\n");
  2.2222 +        return;
  2.2223 +    }
  2.2224 +
  2.2225 +    register_ioport_write(addr, size, 1, ioport_write1, s);
  2.2226 +    register_ioport_read(addr, size, 1, ioport_read1, s);
  2.2227 +    register_ioport_write(addr, size, 2, ioport_write2, s);
  2.2228 +    register_ioport_read(addr, size, 2, ioport_read2, s);
  2.2229 +    register_ioport_write(addr, size, 4, ioport_write4, s);
  2.2230 +    register_ioport_read(addr, size, 4, ioport_read4, s);
  2.2231 +
  2.2232 +    s->region_base_addr[region_num] = addr;
  2.2233 +}
  2.2234 +
  2.2235 +/* From FreeBSD */
  2.2236 +#define POLYNOMIAL 0x04c11db6
  2.2237 +static int compute_mcast_idx(const uint8_t *ep)
  2.2238 +{
  2.2239 +    uint32_t crc;
  2.2240 +    int carry, i, j;
  2.2241 +    uint8_t b;
  2.2242 +
  2.2243 +    crc = 0xffffffff;
  2.2244 +    for (i = 0; i < 6; i++) {
  2.2245 +        b = *ep++;
  2.2246 +        for (j = 0; j < 8; j++) {
  2.2247 +            carry = ((crc & 0x80000000L) ? 1 : 0) ^ (b & 0x01);
  2.2248 +            crc <<= 1;
  2.2249 +            b >>= 1;
  2.2250 +            if (carry)
  2.2251 +                crc = ((crc ^ POLYNOMIAL) | carry);
  2.2252 +        }
  2.2253 +    }
  2.2254 +    return (crc >> 26);
  2.2255 +}
  2.2256 +
  2.2257 +/* Eerpro100 receive functions */
  2.2258 +static int e100_can_receive(void *opaque)
  2.2259 +{
  2.2260 +    E100State *s = opaque;
  2.2261 +
  2.2262 +    int is_ready = (GET_RU_STATE == RU_READY);
  2.2263 +    logout("%s\n", is_ready ? "EEPro100 receiver is ready"
  2.2264 +            : "EEPro100 receiver is not ready");
  2.2265 +    return is_ready;
  2.2266 +}
  2.2267 +
  2.2268 +static void e100_receive(void *opaque, const uint8_t * buf, int size)
  2.2269 +{
  2.2270 +    E100State *s = opaque;
  2.2271 +    uint32_t rfd_addr = 0;
  2.2272 +    rfd_t rfd = {0};
  2.2273 +
  2.2274 +
  2.2275 +    if ( GET_RU_STATE != RU_READY )
  2.2276 +    {
  2.2277 +        //logout("RU is not ready. Begin discarding frame(state=%x)\n", GET_RU_STATE);
  2.2278 +        return;
  2.2279 +    }
  2.2280 +
  2.2281 +    rfd_addr = s->ru_base + s->ru_offset;
  2.2282 +    cpu_physical_memory_read(rfd_addr, (uint8_t *)&rfd, sizeof(rfd_t));
  2.2283 +
  2.2284 +    if ( (size > MAX_ETH_FRAME_SIZE+4) )
  2.2285 +    {
  2.2286 +        /* Long frame and configuration byte 18/3 (long receive ok) not set:
  2.2287 +         * Long frames are discarded. */
  2.2288 +        logout("Discard long frame(size=%d)\n", size);
  2.2289 +
  2.2290 +        return;
  2.2291 +    }
  2.2292 +    else if ( !memcmp(buf, s->macaddr, sizeof(s->macaddr)) )
  2.2293 +    {
  2.2294 +        /* The frame is for me */
  2.2295 +        logout("Receive a frame for me(size=%d)\n", size);
  2.2296 +        e100_dump("FRAME:", (uint8_t *)buf, size);
  2.2297 +    }
  2.2298 +    else if ( !memcmp(buf, broadcast_macaddr, sizeof(broadcast_macaddr)) )
  2.2299 +    {
  2.2300 +        if ( s->config.broadcast_dis && !s->config.promiscuous )
  2.2301 +        {
  2.2302 +            logout("Discard a broadcast frame\n");
  2.2303 +            return;
  2.2304 +        }
  2.2305 +
  2.2306 +        /* Broadcast frame */
  2.2307 +        rfd.status |= RX_IA_MATCH;
  2.2308 +        logout("Receive a broadcast frame(size=%d)\n", size);
  2.2309 +    }
  2.2310 +    else if ( s->is_multcast_enable && buf[0] & 0x1 )
  2.2311 +    {
  2.2312 +        int mcast_idx = compute_mcast_idx(buf);
  2.2313 +        if ( !(s->mult_list[mcast_idx >> 3] & (1 << (mcast_idx & 7))) )
  2.2314 +        {
  2.2315 +            logout("Multicast address mismatch, discard\n");
  2.2316 +            return;
  2.2317 +        }
  2.2318 +        logout("Receive a multicast frame(size=%d)\n", size);
  2.2319 +    }
  2.2320 +    else if ( size < 64 && (s->config.dis_short_rx) )
  2.2321 +    {
  2.2322 +        /* From Intel's spec, short frame should be discarded
  2.2323 +         * when configuration byte 7/0 (discard short receive) set.
  2.2324 +         * But this will cause frame lossing such as ICMP frame, ARP frame.
  2.2325 +         * So we check is the frame for me before discarding short frame
  2.2326 +         */
  2.2327 +
  2.2328 +        /* Save Bad Frame bit */
  2.2329 +        if ( s->config.save_bad_frame )
  2.2330 +        {
  2.2331 +            rfd.status |= RX_SHORT;
  2.2332 +            s->statistics.rx_short_frame_errors ++;
  2.2333 +        }
  2.2334 +        logout("Receive a short frame(size=%d), discard it\n", size);
  2.2335 +        return;
  2.2336 +    }
  2.2337 +    else if ( s->config.promiscuous )
  2.2338 +    {
  2.2339 +        /* Promiscuous: receive all. No address match */
  2.2340 +        logout("Received frame in promiscuous mode(size=%d)\n", size);
  2.2341 +        rfd.status |= RX_NO_MATCH;
  2.2342 +    }
  2.2343 +    else
  2.2344 +    {
  2.2345 +        e100_dump("Unknown frame, MAC = ", (uint8_t *)buf, 6);
  2.2346 +        return;
  2.2347 +    }
  2.2348 +    e100_dump("Get frame, MAC = ", (uint8_t *)buf, 6);
  2.2349 +
  2.2350 +    rfd.c = 1;
  2.2351 +    rfd.ok = 1;
  2.2352 +    rfd.f = 1;
  2.2353 +    rfd.eof = 1;
  2.2354 +    rfd.status &= ~RX_COLLISION;
  2.2355 +    rfd.count = size;
  2.2356 +
  2.2357 +    logout("Get a RFD configure:\n"
  2.2358 +            "\tstatus:%#x\n"
  2.2359 +            "\tok:%#x\n" "\tc:%#x\n" "\tsf:%#x\n"
  2.2360 +            "\th:%#x\n" "\ts:%#x\n" "\tel:%#x\n"
  2.2361 +            "\tlink add:%#x\n" "\tactual count:%#x\n"
  2.2362 +            "\tf:%#x\n" "\teof:%#x\n" "\tsize:%#x\n",
  2.2363 +            rfd.status, rfd.ok, rfd.c, rfd.sf, rfd.h,
  2.2364 +            rfd.s, rfd.el, rfd.link_addr, rfd.count,
  2.2365 +            rfd.f, rfd.eof, rfd.size);
  2.2366 +
  2.2367 +    cpu_physical_memory_write(rfd_addr, (uint8_t *)&rfd, sizeof(rfd));
  2.2368 +    cpu_physical_memory_write(rfd_addr + sizeof(rfd_t), buf, size);
  2.2369 +    s->statistics.rx_good_frames ++;
  2.2370 +    s->ru_offset = le32_to_cpu(rfd.link_addr);
  2.2371 +
  2.2372 +    e100_interrupt(s, INT_FR);
  2.2373 +
  2.2374 +    if ( rfd.el || rfd.s )
  2.2375 +    {
  2.2376 +        /* Go to suspend */
  2.2377 +        SET_RU_STATE(RU_SUSPENDED);
  2.2378 +        e100_interrupt(s, INT_RNR);
  2.2379 +        logout("RFD met S or EL bit set, RU go to suspend\n");
  2.2380 +        return;
  2.2381 +    }
  2.2382 +
  2.2383 +    logout("Complete a frame receive(size = %d)\n", size);
  2.2384 +    return;
  2.2385 +}
  2.2386 +
  2.2387 +static void eeprom_init(E100State *s)
  2.2388 +{
  2.2389 +    int i;
  2.2390 +    int chksum = 0;
  2.2391 +    /* Add 64 * 2 EEPROM. i82557 and i82558 support a 64 word EEPROM,
  2.2392 +     * i82559 and later support 64 or 256 word EEPROM. */
  2.2393 +    eeprom_reset(s, EEPROM_RESET_ALL);
  2.2394 +    s->eeprom.addr_len = EEPROM_I82557_ADDRBIT;
  2.2395 +    memcpy(s->eeprom.contents, eeprom_i82557, sizeof(eeprom_i82557));
  2.2396 +    /* Dirver is going to get MAC from eeprom*/
  2.2397 +    memcpy((uint8_t *)s->eeprom.contents, s->macaddr, sizeof(s->macaddr));
  2.2398 +
  2.2399 +    /* The last word in eeprom saving checksum value.
  2.2400 +     * After we update MAC in eeprom, the checksum need be re-calculate
  2.2401 +     * and saved at the end of eeprom
  2.2402 +     */
  2.2403 +    for ( i=0; i<(1<<s->eeprom.addr_len)-1; i++ )
  2.2404 +        chksum += s->eeprom.contents[i];
  2.2405 +    s->eeprom.contents[i] = 0xBABA - chksum;
  2.2406 +
  2.2407 +}
  2.2408 +
  2.2409 +static void e100_init(PCIBus * bus, NICInfo * nd,
  2.2410 +        const char *name, uint32_t device)
  2.2411 +{
  2.2412 +    PCIE100State *d;
  2.2413 +    E100State *s;
  2.2414 +
  2.2415 +    logout("\n");
  2.2416 +
  2.2417 +    d = (PCIE100State *) pci_register_device(bus, name,
  2.2418 +            sizeof(PCIE100State), -1,
  2.2419 +            NULL, NULL);
  2.2420 +
  2.2421 +    s = &d->e100;
  2.2422 +    s->device = device;
  2.2423 +    s->pci_dev = &d->dev;
  2.2424 +
  2.2425 +    pci_reset(s);
  2.2426 +
  2.2427 +
  2.2428 +    /* Handler for memory-mapped I/O */
  2.2429 +    d->e100.mmio_index =
  2.2430 +        cpu_register_io_memory(0, pci_mmio_read, pci_mmio_write, s);
  2.2431 +
  2.2432 +    //CSR Memory mapped base
  2.2433 +    pci_register_io_region(&d->dev, 0, PCI_MEM_SIZE,
  2.2434 +            PCI_ADDRESS_SPACE_MEM | PCI_ADDRESS_SPACE_MEM_PREFETCH,
  2.2435 +            pci_mmio_map);
  2.2436 +    //CSR I/O mapped base
  2.2437 +    pci_register_io_region(&d->dev, 1, PCI_IO_SIZE, PCI_ADDRESS_SPACE_IO,
  2.2438 +            pci_ioport_map);
  2.2439 +    //Flash memory mapped base
  2.2440 +    pci_register_io_region(&d->dev, 2, PCI_FLASH_SIZE, PCI_ADDRESS_SPACE_MEM,
  2.2441 +            pci_mmio_map);
  2.2442 +
  2.2443 +    memcpy(s->macaddr, nd->macaddr, 6);
  2.2444 +    e100_dump("MAC ADDR", (uint8_t *)&s->macaddr[0], 6);
  2.2445 +
  2.2446 +    eeprom_init(s);
  2.2447 +
  2.2448 +    e100_reset(s);
  2.2449 +
  2.2450 +    s->vc = qemu_new_vlan_client(nd->vlan, e100_receive, e100_can_receive, s);
  2.2451 +
  2.2452 +    snprintf(s->vc->info_str, sizeof(s->vc->info_str),
  2.2453 +            "e100 pci macaddr=%02x:%02x:%02x:%02x:%02x:%02x",
  2.2454 +            s->macaddr[0],
  2.2455 +            s->macaddr[1],
  2.2456 +            s->macaddr[2], s->macaddr[3], s->macaddr[4], s->macaddr[5]);
  2.2457 +
  2.2458 +    qemu_register_reset(e100_reset, s);
  2.2459 +
  2.2460 +    register_savevm(name, 0, 3, e100_save, e100_load, s);
  2.2461 +}
  2.2462 +
  2.2463 +void pci_e100_init(PCIBus * bus, NICInfo * nd)
  2.2464 +{
  2.2465 +    e100_init(bus, nd, "e100", i82557C);
  2.2466 +}
  2.2467 +
     3.1 --- a/tools/ioemu/hw/pci.c	Tue Nov 20 11:53:44 2007 -0700
     3.2 +++ b/tools/ioemu/hw/pci.c	Wed Nov 21 09:12:06 2007 -0700
     3.3 @@ -565,6 +565,8 @@ void pci_nic_init(PCIBus *bus, NICInfo *
     3.4          pci_rtl8139_init(bus, nd, devfn);
     3.5      } else if (strcmp(nd->model, "pcnet") == 0) {
     3.6          pci_pcnet_init(bus, nd, devfn);
     3.7 +    } else if (strcmp(nd->model, "e100") == 0) {
     3.8 +        pci_e100_init(bus, nd);
     3.9      } else {
    3.10          fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd->model);
    3.11          exit (1);
     4.1 --- a/xen/arch/x86/hvm/hpet.c	Tue Nov 20 11:53:44 2007 -0700
     4.2 +++ b/xen/arch/x86/hvm/hpet.c	Wed Nov 21 09:12:06 2007 -0700
     4.3 @@ -127,9 +127,13 @@ static inline int hpet_check_access_leng
     4.4  {
     4.5      if ( (addr & (len - 1)) || (len > 8) )
     4.6      {
     4.7 -        gdprintk(XENLOG_ERR, "HPET: access across register boundary: "
     4.8 +        /*
     4.9 +         * According to ICH9 specification, unaligned accesses may result
    4.10 +         * in unexpected behaviour or master abort, but should not crash/hang.
    4.11 +         * Hence we read all-ones, drop writes, and log a warning.
    4.12 +         */
    4.13 +        gdprintk(XENLOG_WARNING, "HPET: access across register boundary: "
    4.14                   "%lx %lx\n", addr, len);
    4.15 -        domain_crash(current->domain);
    4.16          return -EINVAL;
    4.17      }
    4.18  
     5.1 --- a/xen/arch/x86/irq.c	Tue Nov 20 11:53:44 2007 -0700
     5.2 +++ b/xen/arch/x86/irq.c	Wed Nov 21 09:12:06 2007 -0700
     5.3 @@ -15,7 +15,6 @@
     5.4  #include <xen/keyhandler.h>
     5.5  #include <xen/compat.h>
     5.6  #include <asm/current.h>
     5.7 -#include <asm/smpboot.h>
     5.8  #include <asm/iommu.h>
     5.9  
    5.10  /* opt_noirqbalance: If true, software IRQ balancing/affinity is disabled. */
     6.1 --- a/xen/arch/x86/mm.c	Tue Nov 20 11:53:44 2007 -0700
     6.2 +++ b/xen/arch/x86/mm.c	Wed Nov 21 09:12:06 2007 -0700
     6.3 @@ -3007,7 +3007,8 @@ long set_gdt(struct vcpu *v,
     6.4          return -EINVAL;
     6.5  
     6.6      /* Check the pages in the new GDT. */
     6.7 -    for ( i = 0; i < nr_pages; i++ ) {
     6.8 +    for ( i = 0; i < nr_pages; i++ )
     6.9 +    {
    6.10          mfn = frames[i] = gmfn_to_mfn(d, frames[i]);
    6.11          if ( !mfn_valid(mfn) ||
    6.12               !get_page_and_type(mfn_to_page(mfn), d, PGT_gdt_page) )
    6.13 @@ -3073,23 +3074,15 @@ long do_update_descriptor(u64 pa, u64 de
    6.14  
    6.15      *(u64 *)&d = desc;
    6.16  
    6.17 -    LOCK_BIGLOCK(dom);
    6.18 -
    6.19      mfn = gmfn_to_mfn(dom, gmfn);
    6.20      if ( (((unsigned int)pa % sizeof(struct desc_struct)) != 0) ||
    6.21           !mfn_valid(mfn) ||
    6.22           !check_descriptor(dom, &d) )
    6.23 -    {
    6.24 -        UNLOCK_BIGLOCK(dom);
    6.25          return -EINVAL;
    6.26 -    }
    6.27  
    6.28      page = mfn_to_page(mfn);
    6.29      if ( unlikely(!get_page(page, dom)) )
    6.30 -    {
    6.31 -        UNLOCK_BIGLOCK(dom);
    6.32          return -EINVAL;
    6.33 -    }
    6.34  
    6.35      /* Check if the given frame is in use in an unsafe context. */
    6.36      switch ( page->u.inuse.type_info & PGT_type_mask )
    6.37 @@ -3112,7 +3105,7 @@ long do_update_descriptor(u64 pa, u64 de
    6.38  
    6.39      /* All is good so make the update. */
    6.40      gdt_pent = map_domain_page(mfn);
    6.41 -    memcpy(&gdt_pent[offset], &d, 8);
    6.42 +    atomic_write64((uint64_t *)&gdt_pent[offset], *(uint64_t *)&d);
    6.43      unmap_domain_page(gdt_pent);
    6.44  
    6.45      put_page_type(page);
    6.46 @@ -3122,8 +3115,6 @@ long do_update_descriptor(u64 pa, u64 de
    6.47   out:
    6.48      put_page(page);
    6.49  
    6.50 -    UNLOCK_BIGLOCK(dom);
    6.51 -
    6.52      return ret;
    6.53  }
    6.54  
     7.1 --- a/xen/arch/x86/physdev.c	Tue Nov 20 11:53:44 2007 -0700
     7.2 +++ b/xen/arch/x86/physdev.c	Wed Nov 21 09:12:06 2007 -0700
     7.3 @@ -8,7 +8,6 @@
     7.4  #include <xen/event.h>
     7.5  #include <xen/guest_access.h>
     7.6  #include <asm/current.h>
     7.7 -#include <asm/smpboot.h>
     7.8  #include <asm/hypercall.h>
     7.9  #include <public/xen.h>
    7.10  #include <public/physdev.h>
     8.1 --- a/xen/arch/x86/smp.c	Tue Nov 20 11:53:44 2007 -0700
     8.2 +++ b/xen/arch/x86/smp.c	Wed Nov 21 09:12:06 2007 -0700
     8.3 @@ -18,7 +18,6 @@
     8.4  #include <asm/smp.h>
     8.5  #include <asm/mc146818rtc.h>
     8.6  #include <asm/flushtlb.h>
     8.7 -#include <asm/smpboot.h>
     8.8  #include <asm/hardirq.h>
     8.9  #include <asm/ipi.h>
    8.10  #include <asm/hvm/support.h>
     9.1 --- a/xen/arch/x86/traps.c	Tue Nov 20 11:53:44 2007 -0700
     9.2 +++ b/xen/arch/x86/traps.c	Wed Nov 21 09:12:06 2007 -0700
     9.3 @@ -2583,7 +2583,10 @@ void set_system_gate(unsigned int n, voi
     9.4  
     9.5  void set_task_gate(unsigned int n, unsigned int sel)
     9.6  {
     9.7 +    idt_table[n].b = 0;
     9.8 +    wmb(); /* disable gate /then/ rewrite */
     9.9      idt_table[n].a = sel << 16;
    9.10 +    wmb(); /* rewrite /then/ enable gate */
    9.11      idt_table[n].b = 0x8500;
    9.12  }
    9.13  
    10.1 --- a/xen/arch/x86/x86_32/seg_fixup.c	Tue Nov 20 11:53:44 2007 -0700
    10.2 +++ b/xen/arch/x86/x86_32/seg_fixup.c	Wed Nov 21 09:12:06 2007 -0700
    10.3 @@ -42,7 +42,7 @@
    10.4  #define O  OPCODE_BYTE
    10.5  #define M  HAS_MODRM
    10.6  
    10.7 -static unsigned char insn_decode[256] = {
    10.8 +static const unsigned char insn_decode[256] = {
    10.9      /* 0x00 - 0x0F */
   10.10      O|M, O|M, O|M, O|M, X, X, X, X,
   10.11      O|M, O|M, O|M, O|M, X, X, X, X,
   10.12 @@ -69,7 +69,7 @@ static unsigned char insn_decode[256] = 
   10.13      X, X, X, X, X, X, X, X,
   10.14      /* 0x80 - 0x8F */
   10.15      O|M|1, O|M|4, O|M|1, O|M|1, O|M, O|M, O|M, O|M,
   10.16 -    O|M, O|M, O|M, O|M, O|M, O|M, O|M, X,
   10.17 +    O|M, O|M, O|M, O|M, O|M, X|M, O|M, O|M,
   10.18      /* 0x90 - 0x9F */
   10.19      X, X, X, X, X, X, X, X,
   10.20      X, X, X, X, X, X, X, X,
   10.21 @@ -89,17 +89,17 @@ static unsigned char insn_decode[256] = 
   10.22      X, X, X, X, X, X, X, X,
   10.23      X, X, X, X, X, X, X, X,
   10.24      /* 0xF0 - 0xFF */
   10.25 -    X, X, X, X, X, X, X, X,
   10.26 +    X, X, X, X, X, X, O|M, O|M,
   10.27      X, X, X, X, X, X, O|M, O|M
   10.28  };
   10.29  
   10.30 -static unsigned char twobyte_decode[256] = {
   10.31 +static const unsigned char twobyte_decode[256] = {
   10.32      /* 0x00 - 0x0F */
   10.33      X, X, X, X, X, X, X, X,
   10.34      X, X, X, X, X, X, X, X,
   10.35      /* 0x10 - 0x1F */
   10.36      X, X, X, X, X, X, X, X,
   10.37 -    X, X, X, X, X, X, X, X,
   10.38 +    O|M, X, X, X, X, X, X, X,
   10.39      /* 0x20 - 0x2F */
   10.40      X, X, X, X, X, X, X, X,
   10.41      X, X, X, X, X, X, X, X,
   10.42 @@ -122,16 +122,16 @@ static unsigned char twobyte_decode[256]
   10.43      X, X, X, X, X, X, X, X,
   10.44      X, X, X, X, X, X, X, X,
   10.45      /* 0x90 - 0x9F */
   10.46 -    X, X, X, X, X, X, X, X,
   10.47 -    X, X, X, X, X, X, X, X,
   10.48 +    O|M, O|M, O|M, O|M, O|M, O|M, O|M, O|M,
   10.49 +    O|M, O|M, O|M, O|M, O|M, O|M, O|M, O|M,
   10.50      /* 0xA0 - 0xAF */
   10.51 -    X, X, X, X, X, X, X, X,
   10.52 -    X, X, X, X, X, X, X, X,
   10.53 +    X, X, X, O|M, O|M|1, O|M, O|M, X,
   10.54 +    X, X, X, O|M, O|M|1, O|M, X, O|M,
   10.55      /* 0xB0 - 0xBF */
   10.56 -    X, X, X, X, X, X, X, X,
   10.57 -    X, X, X, X, X, X, X, X,
   10.58 +    X, X, X, O|M, X, X, O|M, O|M,
   10.59 +    X, X, O|M|1, O|M, O|M, O|M, O|M, O|M,
   10.60      /* 0xC0 - 0xCF */
   10.61 -    X, X, X, X, X, X, X, X,
   10.62 +    O|M, O|M, X, O|M, X, X, X, O|M,
   10.63      X, X, X, X, X, X, X, X,
   10.64      /* 0xD0 - 0xDF */
   10.65      X, X, X, X, X, X, X, X,
   10.66 @@ -153,24 +153,24 @@ static unsigned char twobyte_decode[256]
   10.67   *  @base  (OUT): Decoded linear base address.
   10.68   *  @limit (OUT): Decoded segment limit, in bytes. 0 == unlimited (4GB).
   10.69   */
   10.70 -int get_baselimit(u16 seg, unsigned long *base, unsigned long *limit)
   10.71 +static int get_baselimit(u16 seg, unsigned long *base, unsigned long *limit)
   10.72  {
   10.73 -    struct vcpu *d = current;
   10.74 -    unsigned long *table, a, b;
   10.75 -    int            ldt = !!(seg & 4);
   10.76 -    int            idx = (seg >> 3) & 8191;
   10.77 +    struct vcpu *curr = current;
   10.78 +    uint32_t    *table, a, b;
   10.79 +    int          ldt = !!(seg & 4);
   10.80 +    int          idx = (seg >> 3) & 8191;
   10.81  
   10.82      /* Get base and check limit. */
   10.83      if ( ldt )
   10.84      {
   10.85 -        table = (unsigned long *)LDT_VIRT_START(d);
   10.86 -        if ( idx >= d->arch.guest_context.ldt_ents )
   10.87 +        table = (uint32_t *)LDT_VIRT_START(curr);
   10.88 +        if ( idx >= curr->arch.guest_context.ldt_ents )
   10.89              goto fail;
   10.90      }
   10.91      else /* gdt */
   10.92      {
   10.93 -        table = (unsigned long *)GDT_VIRT_START(d);
   10.94 -        if ( idx >= d->arch.guest_context.gdt_ents )
   10.95 +        table = (uint32_t *)GDT_VIRT_START(curr);
   10.96 +        if ( idx >= curr->arch.guest_context.gdt_ents )
   10.97              goto fail;
   10.98      }
   10.99  
  10.100 @@ -204,7 +204,7 @@ int get_baselimit(u16 seg, unsigned long
  10.101  }
  10.102  
  10.103  /* Turn a segment+offset into a linear address. */
  10.104 -int linearise_address(u16 seg, unsigned long off, unsigned long *linear)
  10.105 +static int linearise_address(u16 seg, unsigned long off, unsigned long *linear)
  10.106  {
  10.107      unsigned long base, limit;
  10.108  
  10.109 @@ -219,31 +219,31 @@ int linearise_address(u16 seg, unsigned 
  10.110      return 1;
  10.111  }
  10.112  
  10.113 -int fixup_seg(u16 seg, unsigned long offset)
  10.114 +static int fixup_seg(u16 seg, unsigned long offset)
  10.115  {
  10.116 -    struct vcpu *d = current;
  10.117 -    unsigned long *table, a, b, base, limit;
  10.118 -    int            ldt = !!(seg & 4);
  10.119 -    int            idx = (seg >> 3) & 8191;
  10.120 +    struct vcpu *curr = current;
  10.121 +    uint32_t    *table, a, b, base, limit;
  10.122 +    int          ldt = !!(seg & 4);
  10.123 +    int          idx = (seg >> 3) & 8191;
  10.124  
  10.125      /* Get base and check limit. */
  10.126      if ( ldt )
  10.127      {
  10.128 -        table = (unsigned long *)LDT_VIRT_START(d);
  10.129 -        if ( idx >= d->arch.guest_context.ldt_ents )
  10.130 +        table = (uint32_t *)LDT_VIRT_START(curr);
  10.131 +        if ( idx >= curr->arch.guest_context.ldt_ents )
  10.132          {
  10.133              dprintk(XENLOG_DEBUG, "Segment %04x out of LDT range (%ld)\n",
  10.134 -                    seg, d->arch.guest_context.ldt_ents);
  10.135 +                    seg, curr->arch.guest_context.ldt_ents);
  10.136              goto fail;
  10.137          }
  10.138      }
  10.139      else /* gdt */
  10.140      {
  10.141 -        table = (unsigned long *)GDT_VIRT_START(d);
  10.142 -        if ( idx >= d->arch.guest_context.gdt_ents )
  10.143 +        table = (uint32_t *)GDT_VIRT_START(curr);
  10.144 +        if ( idx >= curr->arch.guest_context.gdt_ents )
  10.145          {
  10.146              dprintk(XENLOG_DEBUG, "Segment %04x out of GDT range (%ld)\n",
  10.147 -                    seg, d->arch.guest_context.gdt_ents);
  10.148 +                    seg, curr->arch.guest_context.gdt_ents);
  10.149              goto fail;
  10.150          }
  10.151      }
  10.152 @@ -261,7 +261,7 @@ int fixup_seg(u16 seg, unsigned long off
  10.153                 _SEGMENT_G|_SEGMENT_CODE|_SEGMENT_DPL)) != 
  10.154           (_SEGMENT_P|_SEGMENT_S|_SEGMENT_DB|_SEGMENT_G|_SEGMENT_DPL) )
  10.155      {
  10.156 -        dprintk(XENLOG_DEBUG, "Bad segment %08lx:%08lx\n", a, b);
  10.157 +        dprintk(XENLOG_DEBUG, "Bad segment %08x:%08x\n", a, b);
  10.158          goto fail;
  10.159      }
  10.160  
  10.161 @@ -291,8 +291,7 @@ int fixup_seg(u16 seg, unsigned long off
  10.162          }
  10.163      }
  10.164  
  10.165 -    dprintk(XENLOG_DEBUG, "None of the above! "
  10.166 -            "(%08lx:%08lx, %08lx, %08lx, %08lx)\n",
  10.167 +    dprintk(XENLOG_DEBUG, "None of the above! (%08x:%08x, %08x, %08x, %08x)\n",
  10.168              a, b, base, limit, base+limit);
  10.169  
  10.170   fail:
  10.171 @@ -303,9 +302,8 @@ int fixup_seg(u16 seg, unsigned long off
  10.172      a &= ~0x0ffff; a |= limit & 0x0ffff;
  10.173      b &= ~0xf0000; b |= limit & 0xf0000;
  10.174      b ^= _SEGMENT_EC; /* grows-up <-> grows-down */
  10.175 -    /* NB. These can't fault. Checked readable above; must also be writable. */
  10.176 -    table[2*idx+0] = a;
  10.177 -    table[2*idx+1] = b;
  10.178 +    /* NB. This can't fault. Checked readable above; must also be writable. */
  10.179 +    atomic_write64((uint64_t *)&table[2*idx], ((uint64_t)b<<32) | a);
  10.180      return 1;
  10.181  }
  10.182  
  10.183 @@ -315,18 +313,15 @@ int fixup_seg(u16 seg, unsigned long off
  10.184   */
  10.185  int gpf_emulate_4gb(struct cpu_user_regs *regs)
  10.186  {
  10.187 -    struct vcpu *d = current;
  10.188 -    struct trap_info   *ti;
  10.189 -    struct trap_bounce *tb;
  10.190 -    u8            modrm, mod, reg, rm, decode;
  10.191 -    void         *memreg;
  10.192 -    unsigned long offset;
  10.193 -    u8            disp8;
  10.194 -    u32           disp32 = 0;
  10.195 +    struct vcpu   *curr = current;
  10.196 +    u8             modrm, mod, rm, decode;
  10.197 +    const u32     *base, *index = NULL;
  10.198 +    unsigned long  offset;
  10.199 +    s8             disp8;
  10.200 +    s32            disp32 = 0;
  10.201      u8            *eip;         /* ptr to instruction start */
  10.202      u8            *pb, b;       /* ptr into instr. / current instr. byte */
  10.203 -    int            gs_override = 0;
  10.204 -    int            twobyte = 0;
  10.205 +    int            gs_override = 0, scale = 0, twobyte = 0;
  10.206  
  10.207      /* WARNING: We only work for ring-3 segments. */
  10.208      if ( unlikely(vm86_mode(regs)) || unlikely(!ring_3(regs)) )
  10.209 @@ -357,6 +352,9 @@ int gpf_emulate_4gb(struct cpu_user_regs
  10.210              goto fail;
  10.211          }
  10.212  
  10.213 +        if ( twobyte )
  10.214 +            break;
  10.215 +
  10.216          switch ( b )
  10.217          {
  10.218          case 0x67: /* Address-size override */
  10.219 @@ -375,6 +373,9 @@ int gpf_emulate_4gb(struct cpu_user_regs
  10.220          case 0x65: /* GS override */
  10.221              gs_override = 1;
  10.222              break;
  10.223 +        case 0x0f: /* Not really a prefix byte */
  10.224 +            twobyte = 1;
  10.225 +            break;
  10.226          default: /* Not a prefix byte */
  10.227              goto done_prefix;
  10.228          }
  10.229 @@ -387,32 +388,10 @@ int gpf_emulate_4gb(struct cpu_user_regs
  10.230          goto fail;
  10.231      }
  10.232  
  10.233 -    decode = insn_decode[b]; /* opcode byte */
  10.234 +    decode = (!twobyte ? insn_decode : twobyte_decode)[b];
  10.235      pb++;
  10.236 -    if ( decode == 0 && b == 0x0f )
  10.237 -    {
  10.238 -        twobyte = 1;
  10.239  
  10.240 -        if ( get_user(b, pb) )
  10.241 -        {
  10.242 -            dprintk(XENLOG_DEBUG,
  10.243 -                    "Fault while accessing byte %ld of instruction\n",
  10.244 -                    (long)(pb-eip));
  10.245 -            goto page_fault;
  10.246 -        }
  10.247 -
  10.248 -        if ( (pb - eip) >= 15 )
  10.249 -        {
  10.250 -            dprintk(XENLOG_DEBUG, "Too many opcode bytes for a "
  10.251 -                    "legal instruction\n");
  10.252 -            goto fail;
  10.253 -        }
  10.254 -
  10.255 -        decode = twobyte_decode[b];
  10.256 -        pb++;
  10.257 -    }
  10.258 -
  10.259 -    if ( decode == 0 )
  10.260 +    if ( !(decode & OPCODE_BYTE) )
  10.261      {
  10.262          dprintk(XENLOG_DEBUG, "Unsupported %sopcode %02x\n",
  10.263                  twobyte ? "two byte " : "", b);
  10.264 @@ -422,12 +401,12 @@ int gpf_emulate_4gb(struct cpu_user_regs
  10.265      if ( !(decode & HAS_MODRM) )
  10.266      {
  10.267          /* Must be a <disp32>, or bail. */
  10.268 -        if ( (decode & 7) != 4 )
  10.269 +        if ( (decode & INSN_SUFFIX_BYTES) != 4 )
  10.270              goto fail;
  10.271  
  10.272          if ( get_user(offset, (u32 *)pb) )
  10.273          {
  10.274 -            dprintk(XENLOG_DEBUG, "Fault while extracting <disp32>.\n");
  10.275 +            dprintk(XENLOG_DEBUG, "Fault while extracting <moffs32>.\n");
  10.276              goto page_fault;
  10.277          }
  10.278          pb += 4;
  10.279 @@ -448,29 +427,39 @@ int gpf_emulate_4gb(struct cpu_user_regs
  10.280      pb++;
  10.281  
  10.282      mod = (modrm >> 6) & 3;
  10.283 -    reg = (modrm >> 3) & 7;
  10.284      rm  = (modrm >> 0) & 7;
  10.285  
  10.286      if ( rm == 4 )
  10.287      {
  10.288 -        dprintk(XENLOG_DEBUG, "FIXME: Add decoding for the SIB byte.\n");
  10.289 -        goto fixme;
  10.290 +        u8 sib;
  10.291 +
  10.292 +        if ( get_user(sib, pb) )
  10.293 +        {
  10.294 +            dprintk(XENLOG_DEBUG, "Fault while extracting sib byte\n");
  10.295 +            goto page_fault;
  10.296 +        }
  10.297 +
  10.298 +        pb++;
  10.299 +
  10.300 +        rm = sib & 7;
  10.301 +        if ( (sib & 0x38) != 0x20 )
  10.302 +            index = decode_register((sib >> 3) & 7, regs, 0);
  10.303 +        scale = sib >> 6;
  10.304      }
  10.305  
  10.306      /* Decode R/M field. */
  10.307 -    memreg = decode_register(rm,  regs, 0);
  10.308 +    base = decode_register(rm, regs, 0);
  10.309  
  10.310      /* Decode Mod field. */
  10.311 -    switch ( modrm >> 6 )
  10.312 +    switch ( mod )
  10.313      {
  10.314      case 0:
  10.315 -        disp32 = 0;
  10.316          if ( rm == 5 ) /* disp32 rather than (EBP) */
  10.317          {
  10.318 -            memreg = NULL;
  10.319 +            base = NULL;
  10.320              if ( get_user(disp32, (u32 *)pb) )
  10.321              {
  10.322 -                dprintk(XENLOG_DEBUG, "Fault while extracting <disp8>.\n");
  10.323 +                dprintk(XENLOG_DEBUG, "Fault while extracting <base32>.\n");
  10.324                  goto page_fault;
  10.325              }
  10.326              pb += 4;
  10.327 @@ -484,13 +473,13 @@ int gpf_emulate_4gb(struct cpu_user_regs
  10.328              goto page_fault;
  10.329          }
  10.330          pb++;
  10.331 -        disp32 = (disp8 & 0x80) ? (disp8 | ~0xff) : disp8;;
  10.332 +        disp32 = disp8;
  10.333          break;
  10.334  
  10.335      case 2:
  10.336          if ( get_user(disp32, (u32 *)pb) )
  10.337          {
  10.338 -            dprintk(XENLOG_DEBUG, "Fault while extracting <disp8>.\n");
  10.339 +            dprintk(XENLOG_DEBUG, "Fault while extracting <disp32>.\n");
  10.340              goto page_fault;
  10.341          }
  10.342          pb += 4;
  10.343 @@ -502,8 +491,10 @@ int gpf_emulate_4gb(struct cpu_user_regs
  10.344      }
  10.345  
  10.346      offset = disp32;
  10.347 -    if ( memreg != NULL )
  10.348 -        offset += *(u32 *)memreg;
  10.349 +    if ( base != NULL )
  10.350 +        offset += *base;
  10.351 +    if ( index != NULL )
  10.352 +        offset += *index << scale;
  10.353  
  10.354   skip_modrm:
  10.355      if ( !fixup_seg((u16)regs->gs, offset) )
  10.356 @@ -513,10 +504,11 @@ int gpf_emulate_4gb(struct cpu_user_regs
  10.357      perfc_incr(seg_fixups);
  10.358  
  10.359      /* If requested, give a callback on otherwise unused vector 15. */
  10.360 -    if ( VM_ASSIST(d->domain, VMASST_TYPE_4gb_segments_notify) )
  10.361 +    if ( VM_ASSIST(curr->domain, VMASST_TYPE_4gb_segments_notify) )
  10.362      {
  10.363 -        ti  = &d->arch.guest_context.trap_ctxt[15];
  10.364 -        tb  = &d->arch.trap_bounce;
  10.365 +        struct trap_info   *ti  = &curr->arch.guest_context.trap_ctxt[15];
  10.366 +        struct trap_bounce *tb  = &curr->arch.trap_bounce;
  10.367 +
  10.368          tb->flags      = TBF_EXCEPTION | TBF_EXCEPTION_ERRCODE;
  10.369          tb->error_code = pb - eip;
  10.370          tb->cs         = ti->cs;
  10.371 @@ -527,13 +519,6 @@ int gpf_emulate_4gb(struct cpu_user_regs
  10.372  
  10.373      return EXCRET_fault_fixed;
  10.374  
  10.375 - fixme:
  10.376 -    dprintk(XENLOG_DEBUG, "Undecodable instruction "
  10.377 -            "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x "
  10.378 -            "caused GPF(0) at %04x:%08x\n",
  10.379 -            eip[0], eip[1], eip[2], eip[3],
  10.380 -            eip[4], eip[5], eip[6], eip[7],
  10.381 -            regs->cs, regs->eip);
  10.382   fail:
  10.383      return 0;
  10.384  
    11.1 --- a/xen/include/asm-powerpc/smpboot.h	Tue Nov 20 11:53:44 2007 -0700
    11.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.3 @@ -1,21 +0,0 @@
    11.4 -/*
    11.5 - * This program is free software; you can redistribute it and/or modify
    11.6 - * it under the terms of the GNU General Public License as published by
    11.7 - * the Free Software Foundation; either version 2 of the License, or
    11.8 - * (at your option) any later version.
    11.9 - *
   11.10 - * This program is distributed in the hope that it will be useful,
   11.11 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
   11.12 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   11.13 - * GNU General Public License for more details.
   11.14 - *
   11.15 - * You should have received a copy of the GNU General Public License
   11.16 - * along with this program; if not, write to the Free Software
   11.17 - * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
   11.18 - *
   11.19 - * Copyright (C) IBM Corp. 2005
   11.20 - *
   11.21 - * Authors: Jimi Xenidis <jimix@watson.ibm.com>
   11.22 - */
   11.23 -
   11.24 -#include "../asm-x86/smpboot.h"
    12.1 --- a/xen/include/asm-x86/desc.h	Tue Nov 20 11:53:44 2007 -0700
    12.2 +++ b/xen/include/asm-x86/desc.h	Wed Nov 21 09:12:06 2007 -0700
    12.3 @@ -143,6 +143,11 @@ typedef struct {
    12.4  
    12.5  #define _set_gate(gate_addr,type,dpl,addr)               \
    12.6  do {                                                     \
    12.7 +    (gate_addr)->a = 0;                                  \
    12.8 +    wmb(); /* disable gate /then/ rewrite */             \
    12.9 +    (gate_addr)->b =                                     \
   12.10 +        ((unsigned long)(addr) >> 32);                   \
   12.11 +    wmb(); /* rewrite /then/ enable gate */              \
   12.12      (gate_addr)->a =                                     \
   12.13          (((unsigned long)(addr) & 0xFFFF0000UL) << 32) | \
   12.14          ((unsigned long)(dpl) << 45) |                   \
   12.15 @@ -150,49 +155,53 @@ do {                                    
   12.16          ((unsigned long)(addr) & 0xFFFFUL) |             \
   12.17          ((unsigned long)__HYPERVISOR_CS64 << 16) |       \
   12.18          (1UL << 47);                                     \
   12.19 -    (gate_addr)->b =                                     \
   12.20 -        ((unsigned long)(addr) >> 32);                   \
   12.21  } while (0)
   12.22  
   12.23  #define _set_tssldt_desc(desc,addr,limit,type)           \
   12.24  do {                                                     \
   12.25 +    (desc)[0].b = (desc)[1].b = 0;                       \
   12.26 +    wmb(); /* disable entry /then/ rewrite */            \
   12.27      (desc)[0].a =                                        \
   12.28          ((u32)(addr) << 16) | ((u32)(limit) & 0xFFFF);   \
   12.29 +    (desc)[1].a = (u32)(((unsigned long)(addr)) >> 32);  \
   12.30 +    wmb(); /* rewrite /then/ enable entry */             \
   12.31      (desc)[0].b =                                        \
   12.32          ((u32)(addr) & 0xFF000000U) |                    \
   12.33          ((u32)(type) << 8) | 0x8000U |                   \
   12.34          (((u32)(addr) & 0x00FF0000U) >> 16);             \
   12.35 -    (desc)[1].a = (u32)(((unsigned long)(addr)) >> 32);  \
   12.36 -    (desc)[1].b = 0;                                     \
   12.37  } while (0)
   12.38  
   12.39  #elif defined(__i386__)
   12.40  
   12.41  typedef struct desc_struct idt_entry_t;
   12.42  
   12.43 -#define _set_gate(gate_addr,type,dpl,addr) \
   12.44 -do { \
   12.45 -  int __d0, __d1; \
   12.46 -  __asm__ __volatile__ ("movw %%dx,%%ax\n\t" \
   12.47 - "movw %4,%%dx\n\t" \
   12.48 - "movl %%eax,%0\n\t" \
   12.49 - "movl %%edx,%1" \
   12.50 - :"=m" (*((long *) (gate_addr))), \
   12.51 -  "=m" (*(1+(long *) (gate_addr))), "=&a" (__d0), "=&d" (__d1) \
   12.52 - :"i" ((short) (0x8000+(dpl<<13)+(type<<8))), \
   12.53 -  "3" ((char *) (addr)),"2" (__HYPERVISOR_CS << 16)); \
   12.54 +#define _set_gate(gate_addr,type,dpl,addr)               \
   12.55 +do {                                                     \
   12.56 +    (gate_addr)->b = 0;                                  \
   12.57 +    wmb(); /* disable gate /then/ rewrite */             \
   12.58 +    (gate_addr)->a =                                     \
   12.59 +        ((unsigned long)(addr) & 0xFFFFUL) |             \
   12.60 +        ((unsigned long)__HYPERVISOR_CS << 16);          \
   12.61 +    wmb(); /* rewrite /then/ enable gate */              \
   12.62 +    (gate_addr)->b =                                     \
   12.63 +        ((unsigned long)(addr) & 0xFFFF0000UL) |         \
   12.64 +        ((unsigned long)(dpl) << 13) |                   \
   12.65 +        ((unsigned long)(type) << 8) |                   \
   12.66 +        (1UL << 15);                                     \
   12.67  } while (0)
   12.68  
   12.69 -#define _set_tssldt_desc(n,addr,limit,type) \
   12.70 -__asm__ __volatile__ ("movw %w3,0(%2)\n\t" \
   12.71 - "movw %%ax,2(%2)\n\t" \
   12.72 - "rorl $16,%%eax\n\t" \
   12.73 - "movb %%al,4(%2)\n\t" \
   12.74 - "movb %4,5(%2)\n\t" \
   12.75 - "movb $0,6(%2)\n\t" \
   12.76 - "movb %%ah,7(%2)\n\t" \
   12.77 - "rorl $16,%%eax" \
   12.78 - : "=m"(*(n)) : "a" (addr), "r"(n), "ir"(limit), "i"(type|0x80))
   12.79 +#define _set_tssldt_desc(desc,addr,limit,type)           \
   12.80 +do {                                                     \
   12.81 +    (desc)->b = 0;                                       \
   12.82 +    wmb(); /* disable entry /then/ rewrite */            \
   12.83 +    (desc)->a =                                          \
   12.84 +        ((u32)(addr) << 16) | ((u32)(limit) & 0xFFFF);   \
   12.85 +    wmb(); /* rewrite /then/ enable entry */             \
   12.86 +    (desc)->b =                                          \
   12.87 +        ((u32)(addr) & 0xFF000000U) |                    \
   12.88 +        ((u32)(type) << 8) | 0x8000U |                   \
   12.89 +        (((u32)(addr) & 0x00FF0000U) >> 16);             \
   12.90 +} while (0)
   12.91  
   12.92  #endif
   12.93  
    13.1 --- a/xen/include/asm-x86/smpboot.h	Tue Nov 20 11:53:44 2007 -0700
    13.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    13.3 @@ -1,16 +0,0 @@
    13.4 -#ifndef __ASM_SMPBOOT_H
    13.5 -#define __ASM_SMPBOOT_H
    13.6 -
    13.7 -static inline unsigned long apicid_to_phys_cpu_present(int apicid)
    13.8 -{
    13.9 -	return 1UL << apicid;
   13.10 -}
   13.11 -
   13.12 -extern volatile int logical_apicid_2_cpu[];
   13.13 -extern volatile int cpu_2_logical_apicid[];
   13.14 -extern volatile int physical_apicid_2_cpu[];
   13.15 -extern volatile int cpu_2_physical_apicid[];
   13.16 -
   13.17 -#define boot_apicid_to_cpu(apicid) physical_apicid_2_cpu[apicid]
   13.18 -
   13.19 -#endif
    14.1 --- a/xen/include/asm-x86/system.h	Tue Nov 20 11:53:44 2007 -0700
    14.2 +++ b/xen/include/asm-x86/system.h	Wed Nov 21 09:12:06 2007 -0700
    14.3 @@ -5,69 +5,78 @@
    14.4  #include <xen/types.h>
    14.5  #include <asm/bitops.h>
    14.6  
    14.7 -#define read_segment_register(name)                                     \
    14.8 -({  u16 __sel;                                                          \
    14.9 -    __asm__ __volatile__ ( "movw %%" STR(name) ",%0" : "=r" (__sel) );  \
   14.10 -    __sel;                                                              \
   14.11 +#define read_segment_register(name)                             \
   14.12 +({  u16 __sel;                                                  \
   14.13 +    asm volatile ( "movw %%" STR(name) ",%0" : "=r" (__sel) );  \
   14.14 +    __sel;                                                      \
   14.15  })
   14.16  
   14.17  #define wbinvd() \
   14.18 -	__asm__ __volatile__ ("wbinvd": : :"memory");
   14.19 +    asm volatile ( "wbinvd" : : : "memory" )
   14.20  
   14.21  #define clflush(a) \
   14.22 -	__asm__ __volatile__ ("clflush (%0)": :"r"(a));
   14.23 +    asm volatile ( "clflush (%0)" : : "r"(a) )
   14.24  
   14.25 -#define nop() __asm__ __volatile__ ("nop")
   14.26 +#define nop() \
   14.27 +    asm volatile ( "nop" )
   14.28  
   14.29 -#define xchg(ptr,v) ((__typeof__(*(ptr)))__xchg((unsigned long)(v),(ptr),sizeof(*(ptr))))
   14.30 +#define xchg(ptr,v) \
   14.31 +    ((__typeof__(*(ptr)))__xchg((unsigned long)(v),(ptr),sizeof(*(ptr))))
   14.32  
   14.33  struct __xchg_dummy { unsigned long a[100]; };
   14.34  #define __xg(x) ((volatile struct __xchg_dummy *)(x))
   14.35  
   14.36 +#if defined(__i386__)
   14.37 +# include <asm/x86_32/system.h>
   14.38 +#elif defined(__x86_64__)
   14.39 +# include <asm/x86_64/system.h>
   14.40 +#endif
   14.41  
   14.42  /*
   14.43   * Note: no "lock" prefix even on SMP: xchg always implies lock anyway
   14.44   * Note 2: xchg has side effect, so that attribute volatile is necessary,
   14.45   *   but generally the primitive is invalid, *ptr is output argument. --ANK
   14.46   */
   14.47 -static always_inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size)
   14.48 +static always_inline unsigned long __xchg(
   14.49 +    unsigned long x, volatile void *ptr, int size)
   14.50  {
   14.51 -	switch (size) {
   14.52 -		case 1:
   14.53 -			__asm__ __volatile__("xchgb %b0,%1"
   14.54 -				:"=q" (x)
   14.55 -				:"m" (*__xg((volatile void *)ptr)), "0" (x)
   14.56 -				:"memory");
   14.57 -			break;
   14.58 -		case 2:
   14.59 -			__asm__ __volatile__("xchgw %w0,%1"
   14.60 -				:"=r" (x)
   14.61 -				:"m" (*__xg((volatile void *)ptr)), "0" (x)
   14.62 -				:"memory");
   14.63 -			break;
   14.64 +    switch ( size )
   14.65 +    {
   14.66 +    case 1:
   14.67 +        asm volatile ( "xchgb %b0,%1"
   14.68 +                       : "=q" (x)
   14.69 +                       : "m" (*__xg((volatile void *)ptr)), "0" (x)
   14.70 +                       : "memory" );
   14.71 +        break;
   14.72 +    case 2:
   14.73 +        asm volatile ( "xchgw %w0,%1"
   14.74 +                       : "=r" (x)
   14.75 +                       : "m" (*__xg((volatile void *)ptr)), "0" (x)
   14.76 +                       : "memory" );
   14.77 +        break;
   14.78  #if defined(__i386__)
   14.79 -		case 4:
   14.80 -			__asm__ __volatile__("xchgl %0,%1"
   14.81 -				:"=r" (x)
   14.82 -				:"m" (*__xg((volatile void *)ptr)), "0" (x)
   14.83 -				:"memory");
   14.84 -			break;
   14.85 +    case 4:
   14.86 +        asm volatile ( "xchgl %0,%1"
   14.87 +                       : "=r" (x)
   14.88 +                       : "m" (*__xg((volatile void *)ptr)), "0" (x)
   14.89 +                       : "memory" );
   14.90 +        break;
   14.91  #elif defined(__x86_64__)
   14.92 -		case 4:
   14.93 -			__asm__ __volatile__("xchgl %k0,%1"
   14.94 -				:"=r" (x)
   14.95 -				:"m" (*__xg((volatile void *)ptr)), "0" (x)
   14.96 -				:"memory");
   14.97 -			break;
   14.98 -		case 8:
   14.99 -			__asm__ __volatile__("xchgq %0,%1"
  14.100 -				:"=r" (x)
  14.101 -				:"m" (*__xg((volatile void *)ptr)), "0" (x)
  14.102 -				:"memory");
  14.103 -			break;
  14.104 +    case 4:
  14.105 +        asm volatile ( "xchgl %k0,%1"
  14.106 +                       : "=r" (x)
  14.107 +                       : "m" (*__xg((volatile void *)ptr)), "0" (x)
  14.108 +                       : "memory" );
  14.109 +        break;
  14.110 +    case 8:
  14.111 +        asm volatile ( "xchgq %0,%1"
  14.112 +                       : "=r" (x)
  14.113 +                       : "m" (*__xg((volatile void *)ptr)), "0" (x)
  14.114 +                       : "memory" );
  14.115 +        break;
  14.116  #endif
  14.117 -	}
  14.118 -	return x;
  14.119 +    }
  14.120 +    return x;
  14.121  }
  14.122  
  14.123  /*
  14.124 @@ -79,230 +88,88 @@ static always_inline unsigned long __xch
  14.125  static always_inline unsigned long __cmpxchg(
  14.126      volatile void *ptr, unsigned long old, unsigned long new, int size)
  14.127  {
  14.128 -	unsigned long prev;
  14.129 -	switch (size) {
  14.130 -	case 1:
  14.131 -		__asm__ __volatile__(LOCK_PREFIX "cmpxchgb %b1,%2"
  14.132 -				     : "=a"(prev)
  14.133 -				     : "q"(new), "m"(*__xg((volatile void *)ptr)), "0"(old)
  14.134 -				     : "memory");
  14.135 -		return prev;
  14.136 -	case 2:
  14.137 -		__asm__ __volatile__(LOCK_PREFIX "cmpxchgw %w1,%2"
  14.138 -				     : "=a"(prev)
  14.139 -				     : "r"(new), "m"(*__xg((volatile void *)ptr)), "0"(old)
  14.140 -				     : "memory");
  14.141 -		return prev;
  14.142 +    unsigned long prev;
  14.143 +    switch ( size )
  14.144 +    {
  14.145 +    case 1:
  14.146 +        asm volatile ( LOCK_PREFIX "cmpxchgb %b1,%2"
  14.147 +                       : "=a" (prev)
  14.148 +                       : "q" (new), "m" (*__xg((volatile void *)ptr)),
  14.149 +                       "0" (old)
  14.150 +                       : "memory" );
  14.151 +        return prev;
  14.152 +    case 2:
  14.153 +        asm volatile ( LOCK_PREFIX "cmpxchgw %w1,%2"
  14.154 +                       : "=a" (prev)
  14.155 +                       : "r" (new), "m" (*__xg((volatile void *)ptr)),
  14.156 +                       "0" (old)
  14.157 +                       : "memory" );
  14.158 +        return prev;
  14.159  #if defined(__i386__)
  14.160 -	case 4:
  14.161 -		__asm__ __volatile__(LOCK_PREFIX "cmpxchgl %1,%2"
  14.162 -				     : "=a"(prev)
  14.163 -				     : "r"(new), "m"(*__xg((volatile void *)ptr)), "0"(old)
  14.164 -				     : "memory");
  14.165 -		return prev;
  14.166 +    case 4:
  14.167 +        asm volatile ( LOCK_PREFIX "cmpxchgl %1,%2"
  14.168 +                       : "=a" (prev)
  14.169 +                       : "r" (new), "m" (*__xg((volatile void *)ptr)),
  14.170 +                       "0" (old)
  14.171 +                       : "memory" );
  14.172 +        return prev;
  14.173  #elif defined(__x86_64__)
  14.174 -	case 4:
  14.175 -		__asm__ __volatile__(LOCK_PREFIX "cmpxchgl %k1,%2"
  14.176 -				     : "=a"(prev)
  14.177 -				     : "r"(new), "m"(*__xg((volatile void *)ptr)), "0"(old)
  14.178 -				     : "memory");
  14.179 -		return prev;
  14.180 -	case 8:
  14.181 -		__asm__ __volatile__(LOCK_PREFIX "cmpxchgq %1,%2"
  14.182 -				     : "=a"(prev)
  14.183 -				     : "r"(new), "m"(*__xg((volatile void *)ptr)), "0"(old)
  14.184 -				     : "memory");
  14.185 -		return prev;
  14.186 +    case 4:
  14.187 +        asm volatile ( LOCK_PREFIX "cmpxchgl %k1,%2"
  14.188 +                       : "=a" (prev)
  14.189 +                       : "r" (new), "m" (*__xg((volatile void *)ptr)),
  14.190 +                       "0" (old)
  14.191 +                       : "memory" );
  14.192 +        return prev;
  14.193 +    case 8:
  14.194 +        asm volatile ( LOCK_PREFIX "cmpxchgq %1,%2"
  14.195 +                       : "=a" (prev)
  14.196 +                       : "r" (new), "m" (*__xg((volatile void *)ptr)),
  14.197 +                       "0" (old)
  14.198 +                       : "memory" );
  14.199 +        return prev;
  14.200  #endif
  14.201 -	}
  14.202 -	return old;
  14.203 +    }
  14.204 +    return old;
  14.205  }
  14.206  
  14.207  #define __HAVE_ARCH_CMPXCHG
  14.208  
  14.209 -#if BITS_PER_LONG == 64
  14.210 -
  14.211 -#define cmpxchg(ptr,o,n)                                                \
  14.212 -    ((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o),            \
  14.213 -                                   (unsigned long)(n),sizeof(*(ptr))))
  14.214 -#else
  14.215 -
  14.216 -static always_inline unsigned long long __cmpxchg8b(
  14.217 -    volatile void *ptr, unsigned long long old, unsigned long long new)
  14.218 -{
  14.219 -    unsigned long long prev;
  14.220 -    __asm__ __volatile__ (
  14.221 -        LOCK_PREFIX "cmpxchg8b %3"
  14.222 -        : "=A" (prev)
  14.223 -        : "c" ((u32)(new>>32)), "b" ((u32)new),
  14.224 -          "m" (*__xg((volatile void *)ptr)), "0" (old)
  14.225 -        : "memory" );
  14.226 -    return prev;
  14.227 -}
  14.228 -
  14.229 -#define cmpxchg(ptr,o,n)                                \
  14.230 -({                                                      \
  14.231 -    __typeof__(*(ptr)) __prev;                          \
  14.232 -    switch ( sizeof(*(ptr)) ) {                         \
  14.233 -    case 8:                                             \
  14.234 -        __prev = ((__typeof__(*(ptr)))__cmpxchg8b(      \
  14.235 -            (ptr),                                      \
  14.236 -            (unsigned long long)(o),                    \
  14.237 -            (unsigned long long)(n)));                  \
  14.238 -        break;                                          \
  14.239 -    default:                                            \
  14.240 -        __prev = ((__typeof__(*(ptr)))__cmpxchg(        \
  14.241 -            (ptr),                                      \
  14.242 -            (unsigned long)(o),                         \
  14.243 -            (unsigned long)(n),                         \
  14.244 -            sizeof(*(ptr))));                           \
  14.245 -        break;                                          \
  14.246 -    }                                                   \
  14.247 -    __prev;                                             \
  14.248 -})
  14.249 -
  14.250 -#endif
  14.251 -
  14.252 -
  14.253  /*
  14.254 - * This function causes value _o to be changed to _n at location _p.
  14.255 - * If this access causes a fault then we return 1, otherwise we return 0.
  14.256 - * If no fault occurs then _o is updated to the value we saw at _p. If this
  14.257 - * is the same as the initial value of _o then _n is written to location _p.
  14.258 + * Both Intel and AMD agree that, from a programmer's viewpoint:
  14.259 + *  Loads cannot be reordered relative to other loads.
  14.260 + *  Stores cannot be reordered relative to other stores.
  14.261 + * 
  14.262 + * Intel64 Architecture Memory Ordering White Paper
  14.263 + * <http://developer.intel.com/products/processor/manuals/318147.pdf>
  14.264 + * 
  14.265 + * AMD64 Architecture Programmer's Manual, Volume 2: System Programming
  14.266 + * <http://www.amd.com/us-en/assets/content_type/\
  14.267 + *  white_papers_and_tech_docs/24593.pdf>
  14.268   */
  14.269 -#ifdef __i386__
  14.270 -#define __cmpxchg_user(_p,_o,_n,_isuff,_oppre,_regtype)                 \
  14.271 -    __asm__ __volatile__ (                                              \
  14.272 -        "1: " LOCK_PREFIX "cmpxchg"_isuff" %"_oppre"2,%3\n"             \
  14.273 -        "2:\n"                                                          \
  14.274 -        ".section .fixup,\"ax\"\n"                                      \
  14.275 -        "3:     movl $1,%1\n"                                           \
  14.276 -        "       jmp 2b\n"                                               \
  14.277 -        ".previous\n"                                                   \
  14.278 -        ".section __ex_table,\"a\"\n"                                   \
  14.279 -        "       .align 4\n"                                             \
  14.280 -        "       .long 1b,3b\n"                                          \
  14.281 -        ".previous"                                                     \
  14.282 -        : "=a" (_o), "=r" (_rc)                                         \
  14.283 -        : _regtype (_n), "m" (*__xg((volatile void *)_p)), "0" (_o), "1" (0) \
  14.284 -        : "memory");
  14.285 -#define cmpxchg_user(_p,_o,_n)                                          \
  14.286 -({                                                                      \
  14.287 -    int _rc;                                                            \
  14.288 -    switch ( sizeof(*(_p)) ) {                                          \
  14.289 -    case 1:                                                             \
  14.290 -        __cmpxchg_user(_p,_o,_n,"b","b","q");                           \
  14.291 -        break;                                                          \
  14.292 -    case 2:                                                             \
  14.293 -        __cmpxchg_user(_p,_o,_n,"w","w","r");                           \
  14.294 -        break;                                                          \
  14.295 -    case 4:                                                             \
  14.296 -        __cmpxchg_user(_p,_o,_n,"l","","r");                            \
  14.297 -        break;                                                          \
  14.298 -    case 8:                                                             \
  14.299 -        __asm__ __volatile__ (                                          \
  14.300 -            "1: " LOCK_PREFIX "cmpxchg8b %4\n"                          \
  14.301 -            "2:\n"                                                      \
  14.302 -            ".section .fixup,\"ax\"\n"                                  \
  14.303 -            "3:     movl $1,%1\n"                                       \
  14.304 -            "       jmp 2b\n"                                           \
  14.305 -            ".previous\n"                                               \
  14.306 -            ".section __ex_table,\"a\"\n"                               \
  14.307 -            "       .align 4\n"                                         \
  14.308 -            "       .long 1b,3b\n"                                      \
  14.309 -            ".previous"                                                 \
  14.310 -            : "=A" (_o), "=r" (_rc)                                     \
  14.311 -            : "c" ((u32)((u64)(_n)>>32)), "b" ((u32)(_n)),              \
  14.312 -              "m" (*__xg((volatile void *)(_p))), "0" (_o), "1" (0)     \
  14.313 -            : "memory");                                                \
  14.314 -        break;                                                          \
  14.315 -    }                                                                   \
  14.316 -    _rc;                                                                \
  14.317 -})
  14.318 -#else
  14.319 -#define __cmpxchg_user(_p,_o,_n,_isuff,_oppre,_regtype)                 \
  14.320 -    __asm__ __volatile__ (                                              \
  14.321 -        "1: " LOCK_PREFIX "cmpxchg"_isuff" %"_oppre"2,%3\n"             \
  14.322 -        "2:\n"                                                          \
  14.323 -        ".section .fixup,\"ax\"\n"                                      \
  14.324 -        "3:     movl $1,%1\n"                                           \
  14.325 -        "       jmp 2b\n"                                               \
  14.326 -        ".previous\n"                                                   \
  14.327 -        ".section __ex_table,\"a\"\n"                                   \
  14.328 -        "       .align 8\n"                                             \
  14.329 -        "       .quad 1b,3b\n"                                          \
  14.330 -        ".previous"                                                     \
  14.331 -        : "=a" (_o), "=r" (_rc)                                         \
  14.332 -        : _regtype (_n), "m" (*__xg((volatile void *)_p)), "0" (_o), "1" (0) \
  14.333 -        : "memory");
  14.334 -#define cmpxchg_user(_p,_o,_n)                                          \
  14.335 -({                                                                      \
  14.336 -    int _rc;                                                            \
  14.337 -    switch ( sizeof(*(_p)) ) {                                          \
  14.338 -    case 1:                                                             \
  14.339 -        __cmpxchg_user(_p,_o,_n,"b","b","q");                           \
  14.340 -        break;                                                          \
  14.341 -    case 2:                                                             \
  14.342 -        __cmpxchg_user(_p,_o,_n,"w","w","r");                           \
  14.343 -        break;                                                          \
  14.344 -    case 4:                                                             \
  14.345 -        __cmpxchg_user(_p,_o,_n,"l","k","r");                           \
  14.346 -        break;                                                          \
  14.347 -    case 8:                                                             \
  14.348 -        __cmpxchg_user(_p,_o,_n,"q","","r");                            \
  14.349 -        break;                                                          \
  14.350 -    }                                                                   \
  14.351 -    _rc;                                                                \
  14.352 -})
  14.353 -#endif
  14.354 -
  14.355 -#if defined(__i386__)
  14.356 -#define mb() 	__asm__ __volatile__ ("lock; addl $0,0(%%esp)": : :"memory")
  14.357 -#define rmb()	__asm__ __volatile__ ("lock; addl $0,0(%%esp)": : :"memory")
  14.358 -#elif defined(__x86_64__)
  14.359 -#define mb()    __asm__ __volatile__ ("mfence":::"memory")
  14.360 -#define rmb()   __asm__ __volatile__ ("lfence":::"memory")
  14.361 -#endif
  14.362 -#define wmb()	__asm__ __volatile__ ("": : :"memory")
  14.363 +#define rmb()           barrier()
  14.364 +#define wmb()           barrier()
  14.365  
  14.366  #ifdef CONFIG_SMP
  14.367 -#define smp_mb()	mb()
  14.368 -#define smp_rmb()	rmb()
  14.369 -#define smp_wmb()	wmb()
  14.370 +#define smp_mb()        mb()
  14.371 +#define smp_rmb()       rmb()
  14.372 +#define smp_wmb()       wmb()
  14.373  #else
  14.374 -#define smp_mb()	barrier()
  14.375 -#define smp_rmb()	barrier()
  14.376 -#define smp_wmb()	barrier()
  14.377 +#define smp_mb()        barrier()
  14.378 +#define smp_rmb()       barrier()
  14.379 +#define smp_wmb()       barrier()
  14.380  #endif
  14.381  
  14.382  #define set_mb(var, value) do { xchg(&var, value); } while (0)
  14.383  #define set_wmb(var, value) do { var = value; wmb(); } while (0)
  14.384  
  14.385 -/* interrupt control.. */
  14.386 -#if defined(__i386__)
  14.387 -#define __save_flags(x)		__asm__ __volatile__("pushfl ; popl %0":"=g" (x): /* no input */)
  14.388 -#define __restore_flags(x) 	__asm__ __volatile__("pushl %0 ; popfl": /* no output */ :"g" (x):"memory", "cc")
  14.389 -#elif defined(__x86_64__)
  14.390 -#define __save_flags(x)		do { __asm__ __volatile__("# save_flags \n\t pushfq ; popq %q0":"=g" (x): /* no input */ :"memory"); } while (0)
  14.391 -#define __restore_flags(x) 	__asm__ __volatile__("# restore_flags \n\t pushq %0 ; popfq": /* no output */ :"g" (x):"memory", "cc")
  14.392 -#endif
  14.393 -#define __cli() 		__asm__ __volatile__("cli": : :"memory")
  14.394 -#define __sti()			__asm__ __volatile__("sti": : :"memory")
  14.395 +#define local_irq_disable()     asm volatile ( "cli" : : : "memory" )
  14.396 +#define local_irq_enable()      asm volatile ( "sti" : : : "memory" )
  14.397 +
  14.398  /* used in the idle loop; sti takes one instruction cycle to complete */
  14.399 -#define safe_halt()		__asm__ __volatile__("sti; hlt": : :"memory")
  14.400 +#define safe_halt()     asm volatile ( "sti; hlt" : : : "memory" )
  14.401  /* used when interrupts are already enabled or to shutdown the processor */
  14.402 -#define halt()			__asm__ __volatile__("hlt": : :"memory")
  14.403 -
  14.404 -/* For spinlocks etc */
  14.405 -#if defined(__i386__)
  14.406 -#define local_irq_save(x)	__asm__ __volatile__("pushfl ; popl %0 ; cli":"=g" (x): /* no input */ :"memory")
  14.407 -#define local_irq_restore(x)	__restore_flags(x)
  14.408 -#elif defined(__x86_64__)
  14.409 -#define local_irq_save(x) 	do { __asm__ __volatile__("# local_irq_save \n\t pushfq ; popq %0 ; cli":"=g" (x): /* no input */ :"memory"); } while (0)
  14.410 -#define local_irq_restore(x)	__asm__ __volatile__("# local_irq_restore \n\t pushq %0 ; popfq": /* no output */ :"g" (x):"memory")
  14.411 -#endif
  14.412 -#define local_irq_disable()	__cli()
  14.413 -#define local_irq_enable()	__sti()
  14.414 +#define halt()          asm volatile ( "hlt" : : : "memory" )
  14.415  
  14.416  static inline int local_irq_is_enabled(void)
  14.417  {
  14.418 @@ -311,8 +178,8 @@ static inline int local_irq_is_enabled(v
  14.419      return !!(flags & (1<<9)); /* EFLAGS_IF */
  14.420  }
  14.421  
  14.422 -#define BROKEN_ACPI_Sx		0x0001
  14.423 -#define BROKEN_INIT_AFTER_S1	0x0002
  14.424 +#define BROKEN_ACPI_Sx          0x0001
  14.425 +#define BROKEN_INIT_AFTER_S1    0x0002
  14.426  
  14.427  void trap_init(void);
  14.428  void percpu_traps_init(void);
    15.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    15.2 +++ b/xen/include/asm-x86/x86_32/system.h	Wed Nov 21 09:12:06 2007 -0700
    15.3 @@ -0,0 +1,114 @@
    15.4 +#ifndef __X86_32_SYSTEM_H__
    15.5 +#define __X86_32_SYSTEM_H__
    15.6 +
    15.7 +static always_inline unsigned long long __cmpxchg8b(
    15.8 +    volatile void *ptr, unsigned long long old, unsigned long long new)
    15.9 +{
   15.10 +    unsigned long long prev;
   15.11 +    asm volatile (
   15.12 +        LOCK_PREFIX "cmpxchg8b %3"
   15.13 +        : "=A" (prev)
   15.14 +        : "c" ((u32)(new>>32)), "b" ((u32)new),
   15.15 +          "m" (*__xg((volatile void *)ptr)), "0" (old)
   15.16 +        : "memory" );
   15.17 +    return prev;
   15.18 +}
   15.19 +
   15.20 +#define cmpxchg(ptr,o,n)                                \
   15.21 +({                                                      \
   15.22 +    __typeof__(*(ptr)) __prev;                          \
   15.23 +    switch ( sizeof(*(ptr)) ) {                         \
   15.24 +    case 8:                                             \
   15.25 +        __prev = ((__typeof__(*(ptr)))__cmpxchg8b(      \
   15.26 +            (ptr),                                      \
   15.27 +            (unsigned long long)(o),                    \
   15.28 +            (unsigned long long)(n)));                  \
   15.29 +        break;                                          \
   15.30 +    default:                                            \
   15.31 +        __prev = ((__typeof__(*(ptr)))__cmpxchg(        \
   15.32 +            (ptr),                                      \
   15.33 +            (unsigned long)(o),                         \
   15.34 +            (unsigned long)(n),                         \
   15.35 +            sizeof(*(ptr))));                           \
   15.36 +        break;                                          \
   15.37 +    }                                                   \
   15.38 +    __prev;                                             \
   15.39 +})
   15.40 +
   15.41 +/*
   15.42 + * This function causes value _o to be changed to _n at location _p.
   15.43 + * If this access causes a fault then we return 1, otherwise we return 0.
   15.44 + * If no fault occurs then _o is updated to the value we saw at _p. If this
   15.45 + * is the same as the initial value of _o then _n is written to location _p.
   15.46 + */
   15.47 +#define __cmpxchg_user(_p,_o,_n,_isuff,_oppre,_regtype)                 \
   15.48 +    asm volatile (                                                      \
   15.49 +        "1: " LOCK_PREFIX "cmpxchg"_isuff" %"_oppre"2,%3\n"             \
   15.50 +        "2:\n"                                                          \
   15.51 +        ".section .fixup,\"ax\"\n"                                      \
   15.52 +        "3:     movl $1,%1\n"                                           \
   15.53 +        "       jmp 2b\n"                                               \
   15.54 +        ".previous\n"                                                   \
   15.55 +        ".section __ex_table,\"a\"\n"                                   \
   15.56 +        "       .align 4\n"                                             \
   15.57 +        "       .long 1b,3b\n"                                          \
   15.58 +        ".previous"                                                     \
   15.59 +        : "=a" (_o), "=r" (_rc)                                         \
   15.60 +        : _regtype (_n), "m" (*__xg((volatile void *)_p)), "0" (_o), "1" (0) \
   15.61 +        : "memory");
   15.62 +
   15.63 +#define cmpxchg_user(_p,_o,_n)                                          \
   15.64 +({                                                                      \
   15.65 +    int _rc;                                                            \
   15.66 +    switch ( sizeof(*(_p)) ) {                                          \
   15.67 +    case 1:                                                             \
   15.68 +        __cmpxchg_user(_p,_o,_n,"b","b","q");                           \
   15.69 +        break;                                                          \
   15.70 +    case 2:                                                             \
   15.71 +        __cmpxchg_user(_p,_o,_n,"w","w","r");                           \
   15.72 +        break;                                                          \
   15.73 +    case 4:                                                             \
   15.74 +        __cmpxchg_user(_p,_o,_n,"l","","r");                            \
   15.75 +        break;                                                          \
   15.76 +    case 8:                                                             \
   15.77 +        asm volatile (                                                  \
   15.78 +            "1: " LOCK_PREFIX "cmpxchg8b %4\n"                          \
   15.79 +            "2:\n"                                                      \
   15.80 +            ".section .fixup,\"ax\"\n"                                  \
   15.81 +            "3:     movl $1,%1\n"                                       \
   15.82 +            "       jmp 2b\n"                                           \
   15.83 +            ".previous\n"                                               \
   15.84 +            ".section __ex_table,\"a\"\n"                               \
   15.85 +            "       .align 4\n"                                         \
   15.86 +            "       .long 1b,3b\n"                                      \
   15.87 +            ".previous"                                                 \
   15.88 +            : "=A" (_o), "=r" (_rc)                                     \
   15.89 +            : "c" ((u32)((u64)(_n)>>32)), "b" ((u32)(_n)),              \
   15.90 +              "m" (*__xg((volatile void *)(_p))), "0" (_o), "1" (0)     \
   15.91 +            : "memory");                                                \
   15.92 +        break;                                                          \
   15.93 +    }                                                                   \
   15.94 +    _rc;                                                                \
   15.95 +})
   15.96 +
   15.97 +static inline void atomic_write64(uint64_t *p, uint64_t v)
   15.98 +{
   15.99 +    uint64_t w = *p, x;
  15.100 +    while ( (x = __cmpxchg8b(p, w, v)) != w )
  15.101 +        w = x;
  15.102 +}
  15.103 +
  15.104 +#define mb()                    \
  15.105 +    asm volatile ( "lock; addl $0,0(%%esp)" : : : "memory" )
  15.106 +
  15.107 +#define __save_flags(x)         \
  15.108 +    asm volatile ( "pushfl ; popl %0" : "=g" (x) : )
  15.109 +#define __restore_flags(x)      \
  15.110 +    asm volatile ( "pushl %0 ; popfl" : : "g" (x) : "memory", "cc" )
  15.111 +
  15.112 +#define local_irq_save(x)       \
  15.113 +    asm volatile ( "pushfl ; popl %0 ; cli" : "=g" (x) : : "memory" )
  15.114 +#define local_irq_restore(x)    \
  15.115 +    __restore_flags(x)
  15.116 +
  15.117 +#endif /* __X86_32_SYSTEM_H__ */
    16.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    16.2 +++ b/xen/include/asm-x86/x86_64/system.h	Wed Nov 21 09:12:06 2007 -0700
    16.3 @@ -0,0 +1,68 @@
    16.4 +#ifndef __X86_64_SYSTEM_H__
    16.5 +#define __X86_64_SYSTEM_H__
    16.6 +
    16.7 +#define cmpxchg(ptr,o,n)                                                \
    16.8 +    ((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o),            \
    16.9 +                                   (unsigned long)(n),sizeof(*(ptr))))
   16.10 +
   16.11 +/*
   16.12 + * This function causes value _o to be changed to _n at location _p.
   16.13 + * If this access causes a fault then we return 1, otherwise we return 0.
   16.14 + * If no fault occurs then _o is updated to the value we saw at _p. If this
   16.15 + * is the same as the initial value of _o then _n is written to location _p.
   16.16 + */
   16.17 +#define __cmpxchg_user(_p,_o,_n,_isuff,_oppre,_regtype)                 \
   16.18 +    asm volatile (                                                      \
   16.19 +        "1: " LOCK_PREFIX "cmpxchg"_isuff" %"_oppre"2,%3\n"             \
   16.20 +        "2:\n"                                                          \
   16.21 +        ".section .fixup,\"ax\"\n"                                      \
   16.22 +        "3:     movl $1,%1\n"                                           \
   16.23 +        "       jmp 2b\n"                                               \
   16.24 +        ".previous\n"                                                   \
   16.25 +        ".section __ex_table,\"a\"\n"                                   \
   16.26 +        "       .align 8\n"                                             \
   16.27 +        "       .quad 1b,3b\n"                                          \
   16.28 +        ".previous"                                                     \
   16.29 +        : "=a" (_o), "=r" (_rc)                                         \
   16.30 +        : _regtype (_n), "m" (*__xg((volatile void *)_p)), "0" (_o), "1" (0) \
   16.31 +        : "memory");
   16.32 +
   16.33 +#define cmpxchg_user(_p,_o,_n)                                          \
   16.34 +({                                                                      \
   16.35 +    int _rc;                                                            \
   16.36 +    switch ( sizeof(*(_p)) ) {                                          \
   16.37 +    case 1:                                                             \
   16.38 +        __cmpxchg_user(_p,_o,_n,"b","b","q");                           \
   16.39 +        break;                                                          \
   16.40 +    case 2:                                                             \
   16.41 +        __cmpxchg_user(_p,_o,_n,"w","w","r");                           \
   16.42 +        break;                                                          \
   16.43 +    case 4:                                                             \
   16.44 +        __cmpxchg_user(_p,_o,_n,"l","k","r");                           \
   16.45 +        break;                                                          \
   16.46 +    case 8:                                                             \
   16.47 +        __cmpxchg_user(_p,_o,_n,"q","","r");                            \
   16.48 +        break;                                                          \
   16.49 +    }                                                                   \
   16.50 +    _rc;                                                                \
   16.51 +})
   16.52 +
   16.53 +static inline void atomic_write64(uint64_t *p, uint64_t v)
   16.54 +{
   16.55 +    *p = v;
   16.56 +}
   16.57 +
   16.58 +#define mb()                    \
   16.59 +    asm volatile ( "mfence" : : : "memory" )
   16.60 +
   16.61 +#define __save_flags(x)         \
   16.62 +    asm volatile ( "pushfq ; popq %q0" : "=g" (x) : :"memory" )
   16.63 +#define __restore_flags(x)      \
   16.64 +    asm volatile ( "pushq %0 ; popfq" : : "g" (x) : "memory", "cc" )
   16.65 +
   16.66 +#define local_irq_save(x)       \
   16.67 +    asm volatile ( "pushfq ; popq %0 ; cli" : "=g" (x) : : "memory" )
   16.68 +#define local_irq_restore(x)    \
   16.69 +    __restore_flags(x)
   16.70 +
   16.71 +#endif /* __X86_64_SYSTEM_H__ */