/* * BSD LICENSE * * Copyright(c) 2017 Cavium, Inc.. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * Neither the name of Cavium, Inc. nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /*$FreeBSD$*/ /* * \brief Host Driver: This file defines the octeon device structure. */ #ifndef _LIO_DEVICE_H_ #define _LIO_DEVICE_H_ #include /* for BYTE_ORDER */ /* PCI VendorId Device Id */ #define LIO_CN23XX_PF_PCIID 0x9702177d /* * Driver identifies chips by these Ids, created by clubbing together * DeviceId+RevisionId; Where Revision Id is not used to distinguish * between chips, a value of 0 is used for revision id. */ #define LIO_CN23XX_PF_VID 0x9702 #define LIO_CN2350_10G_SUBDEVICE 0x03 #define LIO_CN2350_10G_SUBDEVICE1 0x04 #define LIO_CN2360_10G_SUBDEVICE 0x05 #define LIO_CN2350_25G_SUBDEVICE 0x07 #define LIO_CN2360_25G_SUBDEVICE 0x06 /* Endian-swap modes supported by Octeon. */ enum lio_pci_swap_mode { LIO_PCI_PASSTHROUGH = 0, LIO_PCI_SWAP_64BIT = 1, LIO_PCI_SWAP_32BIT = 2, LIO_PCI_LW_SWAP_32BIT = 3 }; enum { LIO_CFG_TYPE_DEFAULT = 0, LIO_NUM_CFGS, }; #define OCTEON_OUTPUT_INTR (2) #define OCTEON_ALL_INTR 0xff /*--------------- PCI BAR1 index registers -------------*/ /* BAR1 Mask */ #define LIO_PCI_BAR1_ENABLE_CA 1 #define LIO_PCI_BAR1_ENDIAN_MODE LIO_PCI_SWAP_64BIT #define LIO_PCI_BAR1_ENTRY_VALID 1 #define LIO_PCI_BAR1_MASK ((LIO_PCI_BAR1_ENABLE_CA << 3) | \ (LIO_PCI_BAR1_ENDIAN_MODE << 1) | \ LIO_PCI_BAR1_ENTRY_VALID) /* * Octeon Device state. * Each octeon device goes through each of these states * as it is initialized. */ #define LIO_DEV_BEGIN_STATE 0x0 #define LIO_DEV_PCI_ENABLE_DONE 0x1 #define LIO_DEV_PCI_MAP_DONE 0x2 #define LIO_DEV_DISPATCH_INIT_DONE 0x3 #define LIO_DEV_INSTR_QUEUE_INIT_DONE 0x4 #define LIO_DEV_SC_BUFF_POOL_INIT_DONE 0x5 #define LIO_DEV_MSIX_ALLOC_VECTOR_DONE 0x6 #define LIO_DEV_RESP_LIST_INIT_DONE 0x7 #define LIO_DEV_DROQ_INIT_DONE 0x8 #define LIO_DEV_INTR_SET_DONE 0xa #define LIO_DEV_IO_QUEUES_DONE 0xb #define LIO_DEV_CONSOLE_INIT_DONE 0xc #define LIO_DEV_HOST_OK 0xd #define LIO_DEV_CORE_OK 0xe #define LIO_DEV_RUNNING 0xf #define LIO_DEV_IN_RESET 0x10 #define LIO_DEV_STATE_INVALID 0x11 #define LIO_DEV_STATES LIO_DEV_STATE_INVALID /* * Octeon Device interrupts * These interrupt bits are set in int_status filed of * octeon_device structure */ #define LIO_DEV_INTR_DMA0_FORCE 0x01 #define LIO_DEV_INTR_DMA1_FORCE 0x02 #define LIO_DEV_INTR_PKT_DATA 0x04 #define LIO_RESET_MSECS (3000) /*---------------------------DISPATCH LIST-------------------------------*/ /* * The dispatch list entry. * The driver keeps a record of functions registered for each * response header opcode in this structure. Since the opcode is * hashed to index into the driver's list, more than one opcode * can hash to the same entry, in which case the list field points * to a linked list with the other entries. */ struct lio_dispatch { /* Singly-linked tail queue node for this entry */ struct lio_stailq_node node; /* Singly-linked tail queue head for this entry */ struct lio_stailq_head head; /* The opcode for which the dispatch function & arg should be used */ uint16_t opcode; /* The function to be called for a packet received by the driver */ lio_dispatch_fn_t dispatch_fn; /* * The application specified argument to be passed to the above * function along with the received packet */ void *arg; }; /* The dispatch list structure. */ struct lio_dispatch_list { /* access to dispatch list must be atomic */ struct mtx lock; /* Count of dispatch functions currently registered */ uint32_t count; /* The list of dispatch functions */ struct lio_dispatch *dlist; }; /*----------------------- THE OCTEON DEVICE ---------------------------*/ #define LIO_MEM_REGIONS 3 /* * PCI address space information. * Each of the 3 address spaces given by BAR0, BAR2 and BAR4 of * Octeon gets mapped to different physical address spaces in * the kernel. */ struct lio_mem_bus_space { struct resource *pci_mem; bus_space_tag_t tag; bus_space_handle_t handle; }; #define LIO_MAX_MAPS 32 struct lio_io_enable { uint64_t iq; uint64_t oq; uint64_t iq64B; }; struct lio_reg_list { uint32_t pci_win_wr_addr; uint32_t pci_win_rd_addr_hi; uint32_t pci_win_rd_addr_lo; uint32_t pci_win_rd_addr; uint32_t pci_win_wr_data_hi; uint32_t pci_win_wr_data_lo; uint32_t pci_win_wr_data; uint32_t pci_win_rd_data; }; #define LIO_MAX_CONSOLE_READ_BYTES 512 typedef int (*octeon_console_print_fn)(struct octeon_device *oct, uint32_t num, char *pre, char *suf); struct lio_console { uint32_t active; uint32_t waiting; uint64_t addr; uint32_t buffer_size; uint64_t input_base_addr; uint64_t output_base_addr; octeon_console_print_fn print; char leftover[LIO_MAX_CONSOLE_READ_BYTES]; }; struct lio_board_info { char name[LIO_BOARD_NAME]; char serial_number[LIO_SERIAL_NUM_LEN]; uint64_t major; uint64_t minor; }; struct lio_fn_list { void (*setup_iq_regs) (struct octeon_device *, uint32_t); void (*setup_oq_regs) (struct octeon_device *, uint32_t); void (*process_interrupt_regs) (void *); uint64_t (*msix_interrupt_handler) (void *); int (*soft_reset) (struct octeon_device *); int (*setup_device_regs) (struct octeon_device *); void (*bar1_idx_setup) (struct octeon_device *, uint64_t, uint32_t, int); void (*bar1_idx_write) (struct octeon_device *, uint32_t, uint32_t); uint32_t (*bar1_idx_read) (struct octeon_device *, uint32_t); uint32_t (*update_iq_read_idx) (struct lio_instr_queue *); void (*enable_interrupt) (struct octeon_device *, uint8_t); void (*disable_interrupt) (struct octeon_device *, uint8_t); int (*enable_io_queues) (struct octeon_device *); void (*disable_io_queues) (struct octeon_device *); }; /* Must be multiple of 8, changing breaks ABI */ #define LIO_BOOTMEM_NAME_LEN 128 /* * Structure for named memory blocks * Number of descriptors * available can be changed without affecting compatibility, * but name length changes require a bump in the bootmem * descriptor version * Note: This structure must be naturally 64 bit aligned, as a single * memory image will be used by both 32 and 64 bit programs. */ struct cvmx_bootmem_named_block_desc { /* Base address of named block */ uint64_t base_addr; /* Size actually allocated for named block */ uint64_t size; /* name of named block */ char name[LIO_BOOTMEM_NAME_LEN]; }; struct lio_fw_info { uint32_t max_nic_ports; /* max nic ports for the device */ uint32_t num_gmx_ports; /* num gmx ports */ uint64_t app_cap_flags; /* firmware cap flags */ /* * The core application is running in this mode. * See octeon-drv-opcodes.h for values. */ uint32_t app_mode; char lio_firmware_version[32]; }; struct lio_callout { struct callout timer; void *ctxptr; uint64_t ctxul; }; #define LIO_NIC_STARTER_TIMEOUT 30000 /* 30000ms (30s) */ struct lio_tq { struct taskqueue *tq; struct timeout_task work; void *ctxptr; uint64_t ctxul; }; struct lio_if_props { /* * Each interface in the Octeon device has a network * device pointer (used for OS specific calls). */ int rx_on; int gmxport; struct ifnet *ifp; }; #define LIO_MSIX_PO_INT 0x1 #define LIO_MSIX_PI_INT 0x2 struct lio_pf_vf_hs_word { #if BYTE_ORDER == LITTLE_ENDIAN /* PKIND value assigned for the DPI interface */ uint64_t pkind:8; /* OCTEON core clock multiplier */ uint64_t core_tics_per_us:16; /* OCTEON coprocessor clock multiplier */ uint64_t coproc_tics_per_us:16; /* app that currently running on OCTEON */ uint64_t app_mode:8; /* RESERVED */ uint64_t reserved:16; #else /* BYTE_ORDER != LITTLE_ENDIAN */ /* RESERVED */ uint64_t reserved:16; /* app that currently running on OCTEON */ uint64_t app_mode:8; /* OCTEON coprocessor clock multiplier */ uint64_t coproc_tics_per_us:16; /* OCTEON core clock multiplier */ uint64_t core_tics_per_us:16; /* PKIND value assigned for the DPI interface */ uint64_t pkind:8; #endif /* BYTE_ORDER == LITTLE_ENDIAN */ }; struct lio_sriov_info { /* Actual rings left for PF device */ uint32_t num_pf_rings; /* SRN of PF usable IO queues */ uint32_t pf_srn; /* total pf rings */ uint32_t trs; }; struct lio_ioq_vector { struct octeon_device *oct_dev; struct resource *msix_res; void *tag; int droq_index; int vector; cpuset_t affinity_mask; uint32_t ioq_num; }; /* * The Octeon device. * Each Octeon device has this structure to represent all its * components. */ struct octeon_device { /* Lock for PCI window configuration accesses */ struct mtx pci_win_lock; /* Lock for memory accesses */ struct mtx mem_access_lock; /* PCI device pointer */ device_t device; /* Chip specific information. */ void *chip; /* Number of interfaces detected in this octeon device. */ uint32_t ifcount; struct lio_if_props props; /* Octeon Chip type. */ uint16_t chip_id; uint16_t rev_id; uint16_t subdevice_id; uint16_t pf_num; /* This device's id - set by the driver. */ uint32_t octeon_id; /* This device's PCIe port used for traffic. */ uint16_t pcie_port; uint16_t flags; #define LIO_FLAG_MSIX_ENABLED (uint32_t)(1 << 2) /* The state of this device */ volatile int status; /* memory mapped io range */ struct lio_mem_bus_space mem_bus_space[LIO_MEM_REGIONS]; struct lio_reg_list reg_list; struct lio_fn_list fn_list; struct lio_board_info boardinfo; uint32_t num_iqs; /* The pool containing pre allocated buffers used for soft commands */ struct lio_sc_buffer_pool sc_buf_pool; /* The input instruction queues */ struct lio_instr_queue *instr_queue[LIO_MAX_POSSIBLE_INSTR_QUEUES]; /* The doubly-linked list of instruction response */ struct lio_response_list response_list[LIO_MAX_RESPONSE_LISTS]; uint32_t num_oqs; /* The DROQ output queues */ struct lio_droq *droq[LIO_MAX_POSSIBLE_OUTPUT_QUEUES]; struct lio_io_enable io_qmask; /* List of dispatch functions */ struct lio_dispatch_list dispatch; uint32_t int_status; /* Physical location of the cvmx_bootmem_desc_t in octeon memory */ uint64_t bootmem_desc_addr; /* * Placeholder memory for named blocks. * Assumes single-threaded access */ struct cvmx_bootmem_named_block_desc bootmem_named_block_desc; /* Address of consoles descriptor */ uint64_t console_desc_addr; /* Number of consoles available. 0 means they are inaccessible */ uint32_t num_consoles; /* Console caches */ struct lio_console console[LIO_MAX_MAPS]; /* Console named block info */ struct { uint64_t dram_region_base; int bar1_index; } console_nb_info; /* Coprocessor clock rate. */ uint64_t coproc_clock_rate; /* * The core application is running in this mode. See lio_common.h * for values. */ uint32_t app_mode; struct lio_fw_info fw_info; /* The name given to this device. */ char device_name[32]; struct lio_tq dma_comp_tq; /* Lock for dma response list */ struct mtx cmd_resp_wqlock; uint32_t cmd_resp_state; struct lio_tq check_db_tq[LIO_MAX_POSSIBLE_INSTR_QUEUES]; struct lio_callout console_timer[LIO_MAX_MAPS]; int num_msix_irqs; /* For PF, there is one non-ioq interrupt handler */ struct resource *msix_res; int aux_vector; void *tag; #define INTRNAMSIZ (32) #define IRQ_NAME_OFF(i) ((i) * INTRNAMSIZ) struct lio_sriov_info sriov_info; struct lio_pf_vf_hs_word pfvf_hsword; int msix_on; /* IOq information of it's corresponding MSI-X interrupt. */ struct lio_ioq_vector *ioq_vector; int rx_pause; int tx_pause; /* TX/RX process pkt budget */ uint32_t rx_budget; uint32_t tx_budget; struct octeon_link_stats link_stats; /* stastics from firmware */ struct proc *watchdog_task; volatile bool cores_crashed; uint32_t rx_coalesce_usecs; uint32_t rx_max_coalesced_frames; uint32_t tx_max_coalesced_frames; #define OCTEON_UBOOT_BUFFER_SIZE 512 char uboot_version[OCTEON_UBOOT_BUFFER_SIZE]; int uboot_len; int uboot_sidx, uboot_eidx; struct { int bus; int dev; int func; } loc; volatile int *adapter_refcount; /* reference count of adapter */ }; #define LIO_DRV_ONLINE 1 #define LIO_DRV_OFFLINE 2 #define LIO_CN23XX_PF(oct) ((oct)->chip_id == LIO_CN23XX_PF_VID) #define LIO_CHIP_CONF(oct, TYPE) \ (((struct lio_ ## TYPE *)((oct)->chip))->conf) #define MAX_IO_PENDING_PKT_COUNT 100 /*------------------ Function Prototypes ----------------------*/ /* Initialize device list memory */ void lio_init_device_list(int conf_type); /* Free memory for Input and Output queue structures for a octeon device */ void lio_free_device_mem(struct octeon_device *oct); /* * Look up a free entry in the octeon_device table and allocate resources * for the octeon_device structure for an octeon device. Called at init * time. */ struct octeon_device *lio_allocate_device(device_t device); /* * Register a device's bus location at initialization time. * @param oct - pointer to the octeon device structure. * @param bus - PCIe bus # * @param dev - PCIe device # * @param func - PCIe function # * @param is_pf - TRUE for PF, FALSE for VF * @return reference count of device's adapter */ int lio_register_device(struct octeon_device *oct, int bus, int dev, int func, int is_pf); /* * Deregister a device at de-initialization time. * @param oct - pointer to the octeon device structure. * @return reference count of device's adapter */ int lio_deregister_device(struct octeon_device *oct); /* * Initialize the driver's dispatch list which is a mix of a hash table * and a linked list. This is done at driver load time. * @param octeon_dev - pointer to the octeon device structure. * @return 0 on success, else -ve error value */ int lio_init_dispatch_list(struct octeon_device *octeon_dev); /* * Delete the driver's dispatch list and all registered entries. * This is done at driver unload time. * @param octeon_dev - pointer to the octeon device structure. */ void lio_delete_dispatch_list(struct octeon_device *octeon_dev); /* * Initialize the core device fields with the info returned by the FW. * @param recv_info - Receive info structure * @param buf - Receive buffer */ int lio_core_drv_init(struct lio_recv_info *recv_info, void *buf); /* * Gets the dispatch function registered to receive packets with a * given opcode/subcode. * @param octeon_dev - the octeon device pointer. * @param opcode - the opcode for which the dispatch function * is to checked. * @param subcode - the subcode for which the dispatch function * is to checked. * * @return Success: lio_dispatch_fn_t (dispatch function pointer) * @return Failure: NULL * * Looks up the dispatch list to get the dispatch function for a * given opcode. */ lio_dispatch_fn_t lio_get_dispatch(struct octeon_device *octeon_dev, uint16_t opcode, uint16_t subcode); /* * Get the octeon device pointer. * @param octeon_id - The id for which the octeon device pointer is required. * @return Success: Octeon device pointer. * @return Failure: NULL. */ struct octeon_device *lio_get_device(uint32_t octeon_id); /* * Get the octeon id assigned to the octeon device passed as argument. * This function is exported to other modules. * @param dev - octeon device pointer passed as a void *. * @return octeon device id */ int lio_get_device_id(void *dev); static inline uint16_t OCTEON_MAJOR_REV(struct octeon_device *oct) { uint16_t rev = (oct->rev_id & 0xC) >> 2; return ((rev == 0) ? 1 : rev); } static inline uint16_t OCTEON_MINOR_REV(struct octeon_device *oct) { return (oct->rev_id & 0x3); } /* * Read windowed register. * @param oct - pointer to the Octeon device. * @param addr - Address of the register to read. * * This routine is called to read from the indirectly accessed * Octeon registers that are visible through a PCI BAR0 mapped window * register. * @return - 64 bit value read from the register. */ uint64_t lio_pci_readq(struct octeon_device *oct, uint64_t addr); /* * Write windowed register. * @param oct - pointer to the Octeon device. * @param val - Value to write * @param addr - Address of the register to write * * This routine is called to write to the indirectly accessed * Octeon registers that are visible through a PCI BAR0 mapped window * register. * @return Nothing. */ void lio_pci_writeq(struct octeon_device *oct, uint64_t val, uint64_t addr); /* * Checks if memory access is okay * * @param oct which octeon to send to * @return Zero on success, negative on failure. */ int lio_mem_access_ok(struct octeon_device *oct); /* * Waits for DDR initialization. * * @param oct which octeon to send to * @param timeout_in_ms pointer to how long to wait until DDR is initialized * in ms. * If contents are 0, it waits until contents are non-zero * before starting to check. * @return Zero on success, negative on failure. */ int lio_wait_for_ddr_init(struct octeon_device *oct, unsigned long *timeout_in_ms); /* * Wait for u-boot to boot and be waiting for a command. * * @param wait_time_hundredths * Maximum time to wait * * @return Zero on success, negative on failure. */ int lio_wait_for_bootloader(struct octeon_device *oct, uint32_t wait_time_hundredths); /* * Initialize console access * * @param oct which octeon initialize * @return Zero on success, negative on failure. */ int lio_init_consoles(struct octeon_device *oct); /* * Adds access to a console to the device. * * @param oct: which octeon to add to * @param console_num: which console * @param dbg_enb: ptr to debug enablement string, one of: * * NULL for no debug output (i.e. disabled) * * empty string enables debug output (via default method) * * specific string to enable debug console output * * @return Zero on success, negative on failure. */ int lio_add_console(struct octeon_device *oct, uint32_t console_num, char *dbg_enb); /* write or read from a console */ int lio_console_write(struct octeon_device *oct, uint32_t console_num, char *buffer, uint32_t write_request_size, uint32_t flags); /* Removes all attached consoles. */ void lio_remove_consoles(struct octeon_device *oct); /* * Send a string to u-boot on console 0 as a command. * * @param oct which octeon to send to * @param cmd_str String to send * @param wait_hundredths Time to wait for u-boot to accept the command. * * @return Zero on success, negative on failure. */ int lio_console_send_cmd(struct octeon_device *oct, char *cmd_str, uint32_t wait_hundredths); /* * Parses, validates, and downloads firmware, then boots associated cores. * @param oct which octeon to download firmware to * @param data - The complete firmware file image * @param size - The size of the data * * @return 0 if success. * -EINVAL if file is incompatible or badly formatted. * -ENODEV if no handler was found for the application type or an * invalid octeon id was passed. */ int lio_download_firmware(struct octeon_device *oct, const uint8_t *data, size_t size); char *lio_get_state_string(volatile int *state_ptr); /* * Sets up instruction queues for the device * @param oct which octeon to setup * * @return 0 if success. 1 if fails */ int lio_setup_instr_queue0(struct octeon_device *oct); /* * Sets up output queues for the device * @param oct which octeon to setup * * @return 0 if success. 1 if fails */ int lio_setup_output_queue0(struct octeon_device *oct); int lio_get_tx_qsize(struct octeon_device *oct, uint32_t q_no); int lio_get_rx_qsize(struct octeon_device *oct, uint32_t q_no); /* * Retrieve the config for the device * @param oct which octeon * @param card_type type of card * * @returns pointer to configuration */ void *lio_get_config_info(struct octeon_device *oct, uint16_t card_type); /* * Gets the octeon device configuration * @return - pointer to the octeon configuration structure */ struct lio_config *lio_get_conf(struct octeon_device *oct); void lio_free_ioq_vector(struct octeon_device *oct); int lio_allocate_ioq_vector(struct octeon_device *oct); void lio_enable_irq(struct lio_droq *droq, struct lio_instr_queue *iq); static inline uint32_t lio_read_pci_cfg(struct octeon_device *oct, uint32_t reg) { return (pci_read_config(oct->device, reg, 4)); } static inline void lio_write_pci_cfg(struct octeon_device *oct, uint32_t reg, uint32_t value) { pci_write_config(oct->device, reg, value, 4); } static inline uint8_t lio_read_csr8(struct octeon_device *oct, uint32_t reg) { return (bus_space_read_1(oct->mem_bus_space[0].tag, oct->mem_bus_space[0].handle, reg)); } static inline void lio_write_csr8(struct octeon_device *oct, uint32_t reg, uint8_t val) { bus_space_write_1(oct->mem_bus_space[0].tag, oct->mem_bus_space[0].handle, reg, val); } static inline uint16_t lio_read_csr16(struct octeon_device *oct, uint32_t reg) { return (bus_space_read_2(oct->mem_bus_space[0].tag, oct->mem_bus_space[0].handle, reg)); } static inline void lio_write_csr16(struct octeon_device *oct, uint32_t reg, uint16_t val) { bus_space_write_2(oct->mem_bus_space[0].tag, oct->mem_bus_space[0].handle, reg, val); } static inline uint32_t lio_read_csr32(struct octeon_device *oct, uint32_t reg) { return (bus_space_read_4(oct->mem_bus_space[0].tag, oct->mem_bus_space[0].handle, reg)); } static inline void lio_write_csr32(struct octeon_device *oct, uint32_t reg, uint32_t val) { bus_space_write_4(oct->mem_bus_space[0].tag, oct->mem_bus_space[0].handle, reg, val); } static inline uint64_t lio_read_csr64(struct octeon_device *oct, uint32_t reg) { #ifdef __i386__ return (lio_read_csr32(oct, reg) | ((uint64_t)lio_read_csr32(oct, reg + 4) << 32)); #else return (bus_space_read_8(oct->mem_bus_space[0].tag, oct->mem_bus_space[0].handle, reg)); #endif } static inline void lio_write_csr64(struct octeon_device *oct, uint32_t reg, uint64_t val) { #ifdef __i386__ lio_write_csr32(oct, reg, (uint32_t)val); lio_write_csr32(oct, reg + 4, val >> 32); #else bus_space_write_8(oct->mem_bus_space[0].tag, oct->mem_bus_space[0].handle, reg, val); #endif } #endif /* _LIO_DEVICE_H_ */