pci_tools.c revision 7851eb825442b34b70077920364eeee5f91c43fa
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <vm/seg_kmem.h>
#include <sys/machparam.h>
#include <sys/pci_cfgspace.h>
#include <sys/pci_tools.h>
#include <sys/pci_tools_var.h>
#include "pci_var.h"
#define SUCCESS 0
int pcitool_debug = 0;
/*
* Offsets of BARS in config space. First entry of 0 means config space.
* Entries here correlate to pcitool_bars_t enumerated type.
*/
0x0,
};
int
{
/* Create pcitool nodes for register access and interrupt routing. */
DDI_NT_REGACC, 0) != DDI_SUCCESS) {
return (DDI_FAILURE);
}
DDI_NT_INTRCTL, 0) != DDI_SUCCESS) {
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
void
{
}
/*
* A note about ontrap handling:
*
* X86 systems on which this module was tested return FFs instead of bus errors
* when accessing devices with invalid addresses. Ontrap handling, which
* gracefully handles kernel bus errors, is installed anyway, in case future
* X86 platforms require it.
*/
/*
* Main function for handling interrupt CPU binding requests and queries.
* Need to implement later
*/
/*ARGSUSED*/
int
{
return (ENOTSUP);
}
/*
* Perform register accesses on the nexus device itself.
* No explicit PCI nexus device for X86, so not applicable.
*/
/*ARGSUSED*/
int
{
return (ENOTSUP);
}
/* Swap endianness. */
static uint64_t
{
typedef union {
} data_split_t;
int i;
returned_data.data64 = 0;
for (i = 0; i < size; i++) {
}
return (returned_data.data64);
}
/* Access device. prg is modified. */
/*ARGSUSED*/
static int
{
/*
* NOTE: there is no way to verify whether or not the address is valid.
* The put functions return void and the get functions return ff on
* error.
*/
if (write_flag) {
if (big_endian) {
} else {
}
switch (size) {
case 1:
break;
case 2:
break;
case 4:
break;
default:
break;
}
} else {
switch (size) {
case 1:
break;
case 2:
break;
case 4:
break;
default:
break;
}
if (big_endian) {
} else {
}
}
}
return (rval);
}
/*ARGSUSED*/
static int
{
/*
* on_trap works like setjmp.
*
* A non-zero return here means on_trap has returned from an error.
*
* A zero return here means that on_trap has just returned from setup.
*/
no_trap();
if (pcitool_debug)
"pcitool_mem_access: on_trap caught an error...\n");
return (EFAULT);
}
if (write_flag) {
if (big_endian) {
} else {
}
if (pcitool_debug)
prom_printf("Writing %ld byte(s) to port 0x%x\n",
switch (size) {
case 1:
break;
case 2:
break;
case 4:
break;
default:
break;
}
} else {
if (pcitool_debug)
prom_printf("Reading %ld byte(s) from port 0x%x\n",
switch (size) {
case 1:
break;
case 2:
break;
case 4:
break;
default:
break;
}
if (big_endian) {
} else {
}
}
}
no_trap();
return (rval);
}
/*ARGSUSED*/
static int
{
int rval = DDI_SUCCESS;
/*
* on_trap works like setjmp.
*
* A non-zero return here means on_trap has returned from an error.
*
* A zero return here means that on_trap has just returned from setup.
*/
no_trap();
if (pcitool_debug)
"pcitool_mem_access: on_trap caught an error...\n");
return (EFAULT);
}
if (write_flag) {
if (big_endian) {
} else {
}
switch (size) {
case 1:
break;
case 2:
break;
case 4:
break;
case 8:
break;
default:
break;
}
} else {
switch (size) {
case 1:
break;
case 2:
break;
case 4:
break;
case 8:
break;
default:
break;
}
if (big_endian) {
} else {
}
}
}
no_trap();
return (rval);
}
/*
* Map up to 2 pages which contain the address we want to access.
*
* Mapping should span no more than 8 bytes. With X86 it is possible for an
* 8 byte value to start on a 4 byte boundary, so it can cross a page boundary.
* We'll never have to map more than two pages.
*/
static uint64_t
{
void *virt_base;
if (pcitool_debug)
prom_printf("pcitool_map: Called with PA:0x%p\n",
*num_pages = 1;
/* Desired mapping would span more than two pages. */
if (pcitool_debug)
prom_printf("boundary violation: "
return (NULL);
(*num_pages)++;
}
/* Get page(s) of virtual space. */
if (pcitool_debug)
prom_printf("Couldn't get virtual base address.\n");
return (NULL);
}
if (pcitool_debug)
/* Now map the allocated virtual space to the physical address. */
if (pcitool_debug)
prom_printf("pcitool_map: returning VA:0x%p\n",
(void *)(uintptr_t)returned_addr);
return (returned_addr);
}
/* Unmap the mapped page(s). */
static void
{
}
/* Perform register accesses on PCI leaf devices. */
int
{
int rval = 0;
switch (cmd) {
case (PCITOOL_DEVICE_SET_REG):
write_flag = B_TRUE;
/*FALLTHRU*/
case (PCITOOL_DEVICE_GET_REG):
if (pcitool_debug)
prom_printf("pci_dev_reg_ops set/get reg\n");
DDI_SUCCESS) {
if (pcitool_debug)
prom_printf("Error reading arguments\n");
return (EFAULT);
}
goto done_reg;
}
if (pcitool_debug)
prom_printf("raw bus:0x%x, dev:0x%x, func:0x%x\n",
/* Validate address arguments of bus / dev / func */
(PCI_REG_BUS_M >> PCI_REG_BUS_SHIFT)) !=
(PCI_REG_DEV_M >> PCI_REG_DEV_SHIFT)) !=
(PCI_REG_FUNC_M >> PCI_REG_FUNC_SHIFT)) !=
goto done_reg;
}
/* Proper config space desired. */
goto done_reg;
}
if (pcitool_debug)
/* Access device. prg is modified. */
if (pcitool_debug)
/* IO/ MEM/ MEM64 space. */
} else {
/*
* Translate BAR number into offset of the BAR in
* the device's config space.
*/
if (pcitool_debug)
/*
* Get Bus Address Register (BAR) from config space.
* prg2.offset is the offset into config space of the
* BAR desired. prg.status is modified on error.
*/
if (pcitool_debug)
prom_printf("BAR access failed\n");
goto done_reg;
}
/*
* Reference proper PCI space based on the BAR.
* If 64 bit MEM space, need to load other half of the
* BAR first.
*/
if (pcitool_debug)
if (pcitool_debug)
prom_printf("BAR data == 0\n");
goto done_reg;
}
if (pcitool_debug)
prom_printf("BAR data == -1\n");
goto done_reg;
}
/*
* BAR has bits saying this space is IO space, unless
* this is the ROM address register.
*/
if (pcitool_debug)
prom_printf("IO space\n");
prom_printf("IO access failed\n");
goto done_reg;
/*
* BAR has bits saying this space is 64 bit memory
* space, unless this is the ROM address register.
*
* The 64 bit address stored in two BAR cells is not
* necessarily aligned on an 8-byte boundary.
* Need to keep the first 4 bytes read,
* and do a separate read of the high 4 bytes.
*/
/*
* Don't try to read the next 4 bytes
* past the end of BARs.
*/
goto done_reg;
}
/*
* Access device.
* prg2.status is modified on error.
*/
goto done_reg;
}
goto done_reg;
}
if (pcitool_debug)
"64 bit mem space. "
/* Mem32 space, including ROM */
} else {
if (pcitool_debug)
"Additional ROM "
"checking\n");
/* Can't write to ROM */
if (write_flag) {
goto done_reg;
/* ROM disabled for reading */
goto done_reg;
}
}
if (pcitool_debug)
prom_printf("32 bit mem space\n");
}
if (pcitool_debug)
/*
* Use offset provided by caller to index into
* desired space, then access.
* Note that prg.status is modified on error.
*/
goto done_reg;
}
}
DDI_SUCCESS) {
if (pcitool_debug)
prom_printf("Error returning arguments.\n");
}
break;
default:
break;
}
return (rval);
}