File: [local] / sys / dev / pci / if_sandrv.c (download)
Revision 1.1.1.1 (vendor branch), Tue Mar 4 16:13:30 2008 UTC (16 years, 5 months ago) by nbrk
Branch: OPENBSD_4_2_BASE, MAIN
CVS Tags: jornada-partial-support-wip, HEAD Changes since 1.1: +0 -0 lines
Import of OpenBSD 4.2 release kernel tree with initial code to support
Jornada 720/728, StrongARM 1110-based handheld PC.
At this point kernel roots on NFS and boots into vfs_mountroot() and traps.
What is supported:
- glass console, Jornada framebuffer (jfb) works in 16bpp direct color mode
(needs some palette tweaks for non black/white/blue colors, i think)
- saic, SA11x0 interrupt controller (needs cleanup)
- sacom, SA11x0 UART (supported only as boot console for now)
- SA11x0 GPIO controller fully supported (but can't handle multiple interrupt
handlers on one gpio pin)
- sassp, SSP port on SA11x0 that attaches spibus
- Jornada microcontroller (jmcu) to control kbd, battery, etc throught
the SPI bus (wskbd attaches on jmcu, but not tested)
- tod functions seem work
- initial code for SA-1111 (chip companion) : this is TODO
Next important steps, i think:
- gpio and intc on sa1111
- pcmcia support for sa11x0 (and sa1111 help logic)
- REAL root on nfs when we have PCMCIA support (we may use any of supported pccard NICs)
- root on wd0! (using already supported PCMCIA-ATA)
|
/* $OpenBSD: if_sandrv.c,v 1.11 2006/04/20 20:31:12 miod Exp $ */
/*-
* Copyright (c) 2001-2004 Sangoma Technologies (SAN)
* All rights reserved. www.sangoma.com
*
* This code is written by Alex Feldman <al.feldman@sangoma.com> for SAN.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. Neither the name of Sangoma Technologies 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 SANGOMA TECHNOLOGIES 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 FOUNDATION 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.
*/
#define __SDLA_HW_LEVEL
#define __SDLADRV__
#include <sys/types.h>
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/syslog.h>
#include <sys/malloc.h>
#include <sys/kernel.h>
#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h>
#include <dev/pci/if_san_front_end.h>
#include <dev/pci/if_sandrv.h>
#define EXEC_DELAY 20 /* shared memory access delay, mks */
#define EXEC_TIMEOUT (hz*2)
#define MAX_NLOOPS (EXEC_DELAY*2000)
/* timeout used if jiffies are stopped
** EXEC_DELAY=20
** EXEC_TIMEOUT=EXEC_DELAY*2000 = 40000
** 40000 ~= 80 jiffies = EXEC_TIMEOUT */
#define EXEC_HZ_DIVISOR 8/10
/* We don't want to wait a full second on sdla_exec
** timeout, thus use HZ * EXEC_HZ_DIVISOR to get
** the number of jiffies we would like to wait */
#define IS_SUPPORTED_ADAPTER(hw) ((hw)->type == SDLA_AFT)
#define SDLA_CTYPE_NAME(type) \
((type) == SDLA_AFT) ? "AFT" : "Unknown"
#define IS_AFT(hw) (hw->type == SDLA_AFT)
/* Definitions for identifying and finding S514 PCI adapters */
#define V3_VENDOR_ID 0x11B0 /* V3 vendor ID number */
#define V3_DEVICE_ID 0x0002 /* V3 device ID number */
#define SANGOMA_SUBSYS_VENDOR 0x4753 /* ID for Sangoma */
/* Definition for identifying and finding XILINX PCI adapters */
#define SANGOMA_PCI_VENDOR 0x1923 /* Old value -> 0x11B0 */
#define SANGOMA_PCI_VENDOR_OLD 0x10EE /* Old value -> 0x11B0 */
#define SANGOMA_PCI_DEVICE 0x0300 /* Old value -> 0x0200 */
#define A101_1TE1_SUBSYS_VENDOR 0xA010 /* A101 with T1/E1 1 line */
#define A101_2TE1_SUBSYS_VENDOR 0xA011 /* A101 with T1/E1 2 lines */
#define A105_T3_SUBSYS_VENDOR 0xA020 /* A102 with T3 */
/* Read PCI SUBVENDOR ID */
#define PCI_SUBVENDOR_MASK 0xFFFF
#define PCI_SUBVENDOR(pa) (pci_conf_read(pa->pa_pc, pa->pa_tag, \
PCI_SUBSYS_ID_REG) & PCI_SUBVENDOR_MASK)
#define PCI_DEVICE_MASK 0xFFFF0000
#define PCI_DEVICE(id) ((id & PCI_DEVICE_MASK ) >> 16)
/* Status values */
#define SDLA_MEM_RESERVED 0x0001
#define SDLA_MEM_MAPPED 0x0002
#define SDLA_IO_MAPPED 0x0004
#define SDLA_PCI_ENABLE 0x0008
struct san_softc {
struct device dev;
struct pci_attach_args pa;
};
typedef struct sdla_hw_probe {
int used;
unsigned char hw_info[100];
LIST_ENTRY(sdla_hw_probe) next;
} sdla_hw_probe_t;
/*
* This structure keeps common parameters per physical card.
*/
typedef struct sdlahw_card {
int used;
unsigned int type; /* S50x/S514/ADSL/XILINX */
unsigned int atype; /* SubVendor ID */
unsigned char core_id; /* SubSystem ID [0..7] */
unsigned char core_rev; /* SubSystem ID [8..15] */
unsigned char pci_extra_ver;
unsigned int slot_no;
unsigned int bus_no;
bus_space_tag_t memt;
struct pci_attach_args pa; /* PCI config header info */
pci_intr_handle_t ih;
LIST_ENTRY(sdlahw_card) next;
} sdlahw_card_t;
/*
* Adapter hardware configuration. Pointer to this structure is passed to all
* APIs.
*/
typedef struct sdlahw {
int used;
unsigned magic;
char devname[20];
u_int16_t status;
int irq; /* interrupt request level */
unsigned int cpu_no; /* PCI CPU Number */
char auto_pci_cfg; /* Auto PCI configuration */
bus_addr_t mem_base_addr;
bus_space_handle_t dpmbase; /* dual-port memory base */
unsigned dpmsize; /* dual-port memory size */
unsigned long memory; /* memory size */
unsigned reserved[5];
unsigned char hw_info[100];
u_int16_t configured;
void *arg; /* card structure */
sdla_hw_probe_t *hwprobe;
sdlahw_card_t *hwcard;
LIST_ENTRY(sdlahw) next;
} sdlahw_t;
/* Entry Point for Low-Level function */
int sdladrv_init(void);
int sdladrv_exit(void);
static int sdla_pci_probe(int, struct pci_attach_args *);
/* PCI bus interface function */
static int sdla_pci_write_config_word(void *, int, u_int16_t);
static int sdla_pci_write_config_dword(void *, int, u_int32_t);
static int sdla_pci_read_config_byte(void *, int, u_int8_t *);
static int sdla_pci_read_config_word(void *, int, u_int16_t *);
static int sdla_pci_read_config_dword(void *, int, u_int32_t *);
static int sdla_detect (sdlahw_t *);
static int sdla_detect_aft(sdlahw_t *);
static int sdla_exec(sdlahw_t *, unsigned long);
static void sdla_peek_by_4(sdlahw_t *, unsigned long, void *, unsigned int);
static void sdla_poke_by_4(sdlahw_t *, unsigned long, void *, unsigned int);
static sdlahw_card_t* sdla_card_register(u_int16_t, int, int);
#if 0
static int sdla_card_unregister (unsigned char, int, int, int);
#endif
static sdlahw_card_t* sdla_card_search(u_int16_t, int, int);
static sdlahw_t* sdla_hw_register(sdlahw_card_t *, int, int, void *);
#if 0
static int sdla_hw_unregister(sdlahw_card_t*, int);
#endif
static sdlahw_t* sdla_hw_search(u_int16_t, int, int, int);
static sdlahw_t* sdla_aft_hw_select (sdlahw_card_t *, int, int,
struct pci_attach_args *);
static void sdla_save_hw_probe (sdlahw_t*, int);
/* SDLA PCI device relative entry point */
int san_match(struct device *, void *, void *);
void san_attach(struct device *, struct device *, void *);
struct cfdriver san_cd = {
NULL, "san", DV_IFNET
};
struct cfattach san_ca = {
sizeof(struct san_softc), san_match, san_attach
};
extern int ticks;
/* SDLA ISA/PCI varibles */
static int Sangoma_cards_no = 0;
static int Sangoma_devices_no = 0;
static int Sangoma_PCI_cards_no = 0;
/* private data */
char *san_drvname = "san";
/* Array of already initialized PCI slots */
static int pci_slot_ar[MAX_S514_CARDS];
LIST_HEAD(, sdlahw_card) sdlahw_card_head =
LIST_HEAD_INITIALIZER(sdlahw_card_head);
LIST_HEAD(, sdlahw) sdlahw_head =
LIST_HEAD_INITIALIZER(sdlahw_head);
LIST_HEAD(, sdla_hw_probe) sdlahw_probe_head =
LIST_HEAD_INITIALIZER(sdlahw_probe_head);
static sdla_hw_type_cnt_t sdla_adapter_cnt;
/*
* PCI Device Driver Entry Points
*/
int
san_match(struct device *parent, void *match, void *aux)
{
struct pci_attach_args* pa = aux;
u_int16_t vendor_id = PCI_VENDOR(pa->pa_id);
u_int16_t device_id = PCI_DEVICE(pa->pa_id);
if ((vendor_id == SANGOMA_PCI_VENDOR ||
vendor_id == SANGOMA_PCI_VENDOR_OLD) &&
device_id == SANGOMA_PCI_DEVICE) {
return (1);
}
return (0);
}
#define PCI_CBIO 0x10
void
san_attach(struct device *parent, struct device *self, void *aux)
{
struct pci_attach_args* pa = aux;
u_int16_t vendor_id = PCI_VENDOR(pa->pa_id);
u_int16_t subvendor_id = PCI_SUBVENDOR(pa);
int atype = 0x00;
atype = PCI_PRODUCT(pci_conf_read(pa->pa_pc, pa->pa_tag,
PCI_SUBSYS_ID_REG));
switch (vendor_id) {
case SANGOMA_PCI_VENDOR_OLD:
case SANGOMA_PCI_VENDOR:
switch (subvendor_id) {
case A101_1TE1_SUBSYS_VENDOR:
atype = A101_ADPTR_1TE1;
break;
case A101_2TE1_SUBSYS_VENDOR:
atype = A101_ADPTR_2TE1;
break;
default:
return;
}
break;
default:
return;
}
if (sdla_pci_probe(atype, pa)) {
printf(": PCI probe FAILED!\n");
return;
}
#ifdef DEBUG
switch (PCI_VENDOR(pa->pa_id)) {
case V3_VENDOR_ID:
switch (atype) {
case S5141_ADPTR_1_CPU_SERIAL:
log(LOG_INFO, "%s: Sangoma S5141/FT1 (Single CPU) "
"adapter\n", self->dv_xname);
break;
case S5142_ADPTR_2_CPU_SERIAL:
log(LOG_INFO, "%s: Sangoma S5142 (Dual CPU) adapter\n",
self->dv_xname);
break;
case S5143_ADPTR_1_CPU_FT1:
log(LOG_INFO, "%s: Sangoma S5143 (Single CPU) "
"FT1 adapter\n", self->dv_xname);
break;
case S5144_ADPTR_1_CPU_T1E1:
case S5148_ADPTR_1_CPU_T1E1:
log(LOG_INFO, "%s: Sangoma S5144 (Single CPU) "
"T1/E1 adapter\n", self->dv_xname);
break;
case S5145_ADPTR_1_CPU_56K:
log(LOG_INFO, "%s: Sangoma S5145 (Single CPU) "
"56K adapter\n", self->dv_xname);
break;
case S5147_ADPTR_2_CPU_T1E1:
log(LOG_INFO, "%s: Sangoma S5147 (Dual CPU) "
"T1/E1 adapter\n", self->dv_xname);
break;
}
break;
case SANGOMA_PCI_VENDOR_OLD:
switch (atype) {
case A101_ADPTR_1TE1:
log(LOG_INFO, "%s: Sangoma AFT (1 channel) "
"T1/E1 adapter\n", self->dv_xname);
break;
case A101_ADPTR_2TE1:
log(LOG_INFO, "%s: Sangoma AFT (2 channels) "
"T1/E1 adapter\n", self->dv_xname);
break;
}
break;
}
#endif
return;
}
/*
* Module init point.
*/
int
sdladrv_init(void)
{
int volatile i = 0;
/* Initialize the PCI Card array, which
* will store flags, used to mark
* card initialization state */
for (i=0; i<MAX_S514_CARDS; i++)
pci_slot_ar[i] = 0xFF;
bzero(&sdla_adapter_cnt, sizeof(sdla_hw_type_cnt_t));
return (0);
}
/*
* Module deinit point.
* o release all remaining system resources
*/
int
sdladrv_exit(void)
{
#if 0
sdla_hw_probe_t *elm_hw_probe;
sdlahw_t *elm_hw;
sdlahw_card_t *elm_hw_card;
elm_hw = LIST_FIRST(&sdlahw_head);
while (elm_hw) {
sdlahw_t *tmp = elm_hw;
elm_hw = LIST_NEXT(elm_hw, next);
if (sdla_hw_unregister(tmp->hwcard, tmp->cpu_no) == EBUSY)
return EBUSY;
}
LIST_INIT(&sdlahw_head);
elm_hw_card = LIST_FIRST(&sdlahw_card_head);
while (elm_hw_card) {
sdlahw_card_t *tmp = elm_hw_card;
elm_hw_card = LIST_NEXT(elm_hw_card, next);
if (sdla_card_unregister(tmp->hw_type,
tmp->slot_no,
tmp->bus_no,
tmp->ioport) == EBUSY)
return EBUSY;
}
LIST_INIT(&sdlahw_card_head);
elm_hw_probe = LIST_FIRST(&sdlahw_probe_head);
while (elm_hw_probe) {
sdla_hw_probe_t *tmp = elm_hw_probe;
elm_hw_probe = LIST_NEXT(elm_hw_probe, next);
if (tmp->used){
log(LOG_INFO, "HW probe info is in used (%s)\n",
elm_hw_probe->hw_info);
return EBUSY;
}
LIST_REMOVE(tmp, next);
free(tmp, M_DEVBUF);
}
#endif
return (0);
}
static void
sdla_save_hw_probe(sdlahw_t *hw, int port)
{
sdla_hw_probe_t *tmp_hw_probe;
tmp_hw_probe = malloc(sizeof(sdla_hw_probe_t), M_DEVBUF, M_NOWAIT);
if (tmp_hw_probe == NULL)
return;
bzero(tmp_hw_probe, sizeof(sdla_hw_probe_t));
snprintf(tmp_hw_probe->hw_info, sizeof(tmp_hw_probe->hw_info),
"%s : SLOT=%d : BUS=%d : IRQ=%d : CPU=%c : PORT=%s",
SDLA_ADPTR_DECODE(hw->hwcard->atype), hw->hwcard->slot_no,
hw->hwcard->bus_no, hw->irq, SDLA_GET_CPU(hw->cpu_no), "PRI");
hw->hwprobe = tmp_hw_probe;
tmp_hw_probe->used++;
LIST_INSERT_HEAD(&sdlahw_probe_head, tmp_hw_probe, next);
}
static sdlahw_t*
sdla_aft_hw_select(sdlahw_card_t *hwcard, int cpu_no,
int irq, struct pci_attach_args *pa)
{
sdlahw_t* hw = NULL;
int number_of_cards = 0;
hwcard->type = SDLA_AFT;
switch (hwcard->atype) {
case A101_ADPTR_1TE1:
hw = sdla_hw_register(hwcard, cpu_no, irq, pa);
sdla_save_hw_probe(hw, 0);
number_of_cards += 1;
#ifdef DEBUG
log(LOG_INFO, "%s: %s T1/E1 card found (%s rev.%d), "
"cpu(s) 1, bus #%d, slot #%d, irq #%d\n", san_drvname,
SDLA_ADPTR_DECODE(hwcard->atype),
AFT_CORE_ID_DECODE(hwcard->core_id), hwcard->core_rev,
hwcard->bus_no, hwcard->slot_no, irq);
#endif /* DEBUG */
break;
case A101_ADPTR_2TE1:
hw = sdla_hw_register(hwcard, cpu_no, irq, pa);
sdla_save_hw_probe(hw, 0);
number_of_cards += 1;
#ifdef DEBUG
log(LOG_INFO, "%s: %s T1/E1 card found (%s rev.%d), "
"cpu(s) 2, bus #%d, slot #%d, irq #%d\n", san_drvname,
SDLA_ADPTR_DECODE(hwcard->atype),
AFT_CORE_ID_DECODE(hwcard->core_id), hwcard->core_rev,
hwcard->bus_no, hwcard->slot_no, irq);
#endif /* DEBUG */
break;
case A105_ADPTR_1_CHN_T3E3:
hw = sdla_hw_register(hwcard, cpu_no, irq, pa);
sdla_save_hw_probe(hw, 0);
number_of_cards += 1;
#ifdef DEBUG
log(LOG_INFO, "%s: %s T3/E3 card found, cpu(s) 1,"
"bus #%d, slot #%d, irq #%d\n", san_drvname,
SDLA_ADPTR_DECODE(hwcard->atype),
hwcard->bus_no, hwcard->slot_no, irq);
#endif /* DEBUG */
break;
default:
log(LOG_INFO, "%s: Unknown adapter %04X "
"(bus #%d, slot #%d, irq #%d)!\n", san_drvname,
hwcard->atype, hwcard->bus_no, hwcard->slot_no, irq);
break;
}
return (hw);
}
static int
sdla_pci_probe(int atype, struct pci_attach_args *pa)
{
sdlahw_card_t* hwcard;
sdlahw_t* hw;
/*sdladev_t* dev = NULL;*/
int dual_cpu = 0;
int bus, slot, cpu = SDLA_CPU_A;
u_int16_t vendor_id, subvendor_id, device_id;
u_int8_t irq;
pci_intr_handle_t ih;
const char* intrstr = NULL;
bus = pa->pa_bus;
slot = pa->pa_device;
vendor_id = PCI_VENDOR(pa->pa_id);
subvendor_id = PCI_SUBVENDOR(pa);
device_id = PCI_DEVICE(pa->pa_id);
irq = (u_int8_t)pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_INTLINE);
/* Map and establish the interrupt */
if (pci_intr_map(pa, &ih)) {
printf(": couldn't map interrupt\n");
return (EINVAL);
}
intrstr = pci_intr_string(pa->pa_pc, ih);
if (intrstr != NULL)
printf(" %s\n", intrstr);
Sangoma_cards_no ++;
reg_new_card:
Sangoma_PCI_cards_no ++;
hwcard = sdla_card_register(atype, slot, bus);
if (hwcard == NULL)
return (EINVAL);
hwcard->memt = pa->pa_memt;
hwcard->ih = ih;
hwcard->pa = *pa;
/* Increment number of available Sangoma devices */
Sangoma_devices_no ++;
switch (atype) {
case A101_ADPTR_1TE1:
case A101_ADPTR_2TE1:
hw = sdla_aft_hw_select(hwcard, cpu, irq, pa);
sdla_adapter_cnt.AFT_adapters++;
if (atype == A101_ADPTR_2TE1)
dual_cpu = 1;
break;
}
if (hw == NULL)
return (EINVAL);
if (san_dev_attach(hw, hw->devname, sizeof(hw->devname)))
return (EINVAL);
hw->used++;
if (dual_cpu && cpu == SDLA_CPU_A) {
cpu = SDLA_CPU_B;
goto reg_new_card;
}
return (0);
}
int
sdla_intr_establish(void *phw, int (*intr_func)(void*), void* intr_arg)
{
sdlahw_t *hw = (sdlahw_t*)phw;
sdlahw_card_t *hwcard;
WAN_ASSERT(hw == NULL);
hwcard = hw->hwcard;
if (pci_intr_establish(hwcard->pa.pa_pc, hwcard->ih, IPL_NET,
intr_func, intr_arg, "san") == NULL)
return (EINVAL);
return 0;
}
int
sdla_intr_disestablish(void *phw)
{
sdlahw_t *hw = (sdlahw_t*)phw;
log(LOG_INFO, "%s: Disestablish interrupt is not defined!\n",
hw->devname);
return (EINVAL);
}
int
sdla_get_hw_devices(void)
{
return (Sangoma_devices_no);
}
void*
sdla_get_hw_adptr_cnt(void)
{
return (&sdla_adapter_cnt);
}
static sdlahw_card_t*
sdla_card_register(u_int16_t atype, int slot_no, int bus_no)
{
sdlahw_card_t *new_hwcard, *last_hwcard;
new_hwcard = sdla_card_search(atype, slot_no, bus_no);
if (new_hwcard)
return (new_hwcard);
new_hwcard = malloc(sizeof(sdlahw_card_t), M_DEVBUF, M_NOWAIT);
if (!new_hwcard)
return (NULL);
bzero(new_hwcard, sizeof(sdlahw_card_t));
new_hwcard->atype = atype;
new_hwcard->slot_no = slot_no;
new_hwcard->bus_no = bus_no;
if (LIST_EMPTY(&sdlahw_card_head)) {
/* Initialize SAN HW parameters */
sdladrv_init();
}
LIST_FOREACH(last_hwcard, &sdlahw_card_head, next) {
if (!LIST_NEXT(last_hwcard, next))
break;
}
if (last_hwcard)
LIST_INSERT_AFTER(last_hwcard, new_hwcard, next);
else
LIST_INSERT_HEAD(&sdlahw_card_head, new_hwcard, next);
return (new_hwcard);
}
#if 0
static int
sdla_card_unregister(u_int16_t atype, int slot_no, int bus_no, int ioport)
{
sdlahw_card_t* tmp_card;
LIST_FOREACH(tmp_card, &sdlahw_card_head, next){
if (tmp_card->atype != atype){
continue;
}
if (tmp_card->slot_no == slot_no &&
tmp_card->bus_no == bus_no){
break;
}
}
if (tmp_card == NULL){
log(LOG_INFO,
"Error: Card didn't find %04X card (slot=%d, bus=%d)\n"
atype, slot_no, bus_no);
return (EFAULT)
}
if (tmp_card->used){
log(LOG_INFO,
"Error: Card is still in used (slot=%d,bus=%d,used=%d)\n",
slot_no, bus_no, tmp_card->used);
return (EBUSY);
}
LIST_REMOVE(tmp_card, next);
free(tmp_card, M_DEVBUF);
return 0;
}
#endif
static sdlahw_card_t*
sdla_card_search(u_int16_t atype, int slot_no, int bus_no)
{
sdlahw_card_t* tmp_card;
LIST_FOREACH(tmp_card, &sdlahw_card_head, next) {
if (tmp_card->atype != atype)
continue;
if (tmp_card->slot_no == slot_no &&
tmp_card->bus_no == bus_no)
return (tmp_card);
}
return (NULL);
}
static sdlahw_t*
sdla_hw_register(sdlahw_card_t *card, int cpu_no, int irq, void *dev)
{
sdlahw_t *new_hw, *last_hw;
new_hw = sdla_hw_search(card->atype, card->slot_no,
card->bus_no, cpu_no);
if (new_hw)
return (new_hw);
new_hw = malloc(sizeof(sdlahw_t), M_DEVBUF, M_NOWAIT);
if (!new_hw)
return (NULL);
bzero(new_hw, sizeof(sdlahw_t));
new_hw->cpu_no = cpu_no;
new_hw->irq = irq;
new_hw->hwcard = card;
#if 0
new_hw->dev = dev;
#endif
new_hw->magic = SDLAHW_MAGIC;
card->used++;
LIST_FOREACH(last_hw, &sdlahw_head, next) {
if (!LIST_NEXT(last_hw, next))
break;
}
if (last_hw)
LIST_INSERT_AFTER(last_hw, new_hw, next);
else
LIST_INSERT_HEAD(&sdlahw_head, new_hw, next);
return (new_hw);
}
#if 0
static int
sdla_hw_unregister(sdlahw_card_t* hwcard, int cpu_no)
{
sdlahw_t* tmp_hw;
int i;
LIST_FOREACH(tmp_hw, &sdlahw_head, next) {
if (tmp_hw->hwcard != hwcard)
continue;
if (tmp_hw->cpu_no == cpu_no)
break;
}
if (tmp_hw == NULL) {
log(LOG_INFO,
"Error: Failed to find device (slot=%d,bus=%d,cpu=%c)\n",
hwcard->slot_no, hwcard->bus_no, SDLA_GET_CPU(cpu_no));
return (EFAULT);
}
if (tmp_hw->used) {
log(LOG_INFO,
"Error: Device is still in used (slot=%d,bus=%d,cpu=%c,%d)\n",
hwcard->slot_no,
hwcard->bus_no,
SDLA_GET_CPU(cpu_no),
hwcard->used);
return (EBUSY);
}
tmp_hw->hwprobe = NULL;
tmp_hw->hwcard = NULL;
hwcard->used--; /* Decrement card usage */
LIST_REMOVE(tmp_hw, next);
free(tmp_hw, M_DEVBUF);
return (0);
}
#endif
static sdlahw_t*
sdla_hw_search(u_int16_t atype, int slot_no, int bus_no, int cpu_no)
{
sdlahw_t* tmp_hw;
LIST_FOREACH(tmp_hw, &sdlahw_head, next) {
if (tmp_hw->hwcard == NULL) {
log(LOG_INFO,
"Critical Error: sdla_cpu_search: line %d\n",
__LINE__);
// XXX REMOVE in LIST_FOREACH
LIST_REMOVE(tmp_hw, next);
continue;
}
if (tmp_hw->hwcard->atype != atype) {
// XXX why ???
LIST_REMOVE(tmp_hw, next);
continue;
}
if (tmp_hw->hwcard->slot_no == slot_no &&
tmp_hw->hwcard->bus_no == bus_no &&
tmp_hw->cpu_no == cpu_no)
return (tmp_hw);
}
return (NULL);
}
/*
* Set up adapter.
* o detect adapter type
* o set up adapter shared memory
* Return: 0 ok.
* < 0 error
*/
int
sdla_setup(void *phw)
{
sdlahw_card_t* hwcard = NULL;
sdlahw_t* hw = (sdlahw_t*)phw;
int err=0;
WAN_ASSERT(hw == NULL);
SDLA_MAGIC(hw);
WAN_ASSERT(hw->hwcard == NULL);
hwcard = hw->hwcard;
switch (hwcard->type) {
case SDLA_AFT:
break;
default:
log(LOG_INFO, "%s: Invalid card type %x\n",
hw->devname, hw->hwcard->type);
return (EINVAL);
}
hw->dpmsize = SDLA_WINDOWSIZE;
err = sdla_detect(hw);
return (err);
}
/*
* Shut down SDLA: disable shared memory access and interrupts, stop CPU, etc.
*/
int
sdla_down(void *phw)
{
sdlahw_card_t* card = NULL;
sdlahw_t* hw = (sdlahw_t*)phw;
WAN_ASSERT(hw == NULL);
SDLA_MAGIC(hw);
WAN_ASSERT(hw->hwcard == NULL);
card = hw->hwcard;
switch (card->type) {
case SDLA_AFT:
/* free up the allocated virtual memory */
if (hw->status & SDLA_MEM_MAPPED) {
bus_space_unmap(hw->hwcard->memt,
hw->dpmbase,
XILINX_PCI_MEM_SIZE);
hw->status &= ~SDLA_MEM_MAPPED;
}
break;
default:
return (EINVAL);
}
return (0);
}
/*
* Read the hardware interrupt status.
*/
int
sdla_read_int_stat(void *phw, u_int32_t *int_status)
{
sdlahw_card_t* card = NULL;
sdlahw_t* hw = (sdlahw_t*)phw;
WAN_ASSERT(hw == NULL);
SDLA_MAGIC(hw);
WAN_ASSERT(hw->hwcard == NULL);
card = hw->hwcard;
switch (card->type) {
case SDLA_AFT:
sdla_pci_read_config_dword(hw, PCI_INT_STATUS, int_status);
}
return (0);
}
/*
* Generate an interrupt to adapter's CPU.
*/
int
sdla_cmd(void *phw, unsigned long offset, wan_mbox_t *mbox)
{
sdlahw_t *hw = (sdlahw_t*)phw;
int len = sizeof(wan_cmd_t);
int err = 0;
u_int8_t value;
SDLA_MAGIC(hw);
len += mbox->wan_data_len;
sdla_peek(hw, offset, (void*)&value, 1);
if (value != 0x00) {
log(LOG_INFO, "%s: opp flag set on entry to sdla_exec!\n",
hw->devname);
return (0);
}
mbox->wan_opp_flag = 0x00;
sdla_poke(hw, offset, (void*)mbox, len);
err = sdla_exec(hw, offset);
if (!err) {
log(LOG_INFO, "%s: Command 0x%02X failed!\n",
hw->devname, mbox->wan_command);
return (WAN_CMD_TIMEOUT);
}
sdla_peek(hw, offset, (void*)mbox, sizeof(wan_cmd_t));
if (mbox->wan_data_len) {
sdla_peek(hw, offset+offsetof(wan_mbox_t, wan_data),
mbox->wan_data, mbox->wan_data_len);
}
return (mbox->wan_return_code);
}
/*
* Execute Adapter Command.
* o Set exec flag.
* o Busy-wait until flag is reset.
* o Return number of loops made, or 0 if command timed out.
*/
static int
sdla_exec(sdlahw_t *hw, unsigned long offset)
{
volatile unsigned long tstop;
volatile unsigned long nloops;
u_int8_t value;
value = 0x01;
sdla_poke(hw, offset, (void*)&value, 1);
tstop = ticks + EXEC_TIMEOUT;
sdla_peek(hw, offset, (void*)&value, 1);
for (nloops = 1; value == 0x01; ++ nloops) {
DELAY(EXEC_DELAY);
if (ticks > tstop || nloops > MAX_NLOOPS) {
log(LOG_INFO, "%s: Timeout %lu ticks (max=%lu) "
"loops %lu (max=%u)\n", hw->devname,
(ticks-tstop+EXEC_TIMEOUT),
(unsigned long)EXEC_TIMEOUT, nloops, MAX_NLOOPS);
return (0); /* time is up! */
}
sdla_peek(hw, offset, (void*)&value, 1);
}
return (nloops);
}
/*
* Read absolute adapter memory.
* Transfer data from adapter's memory to data buffer.
*
* Note:
* Care should be taken when crossing dual-port memory window boundary.
* This function is not atomic, so caller must disable interrupt if
* interrupt routines are accessing adapter shared memory.
*/
int
sdla_peek(void *phw, unsigned long addr, void *buf, unsigned len)
{
sdlahw_card_t* card = NULL;
sdlahw_t* hw = (sdlahw_t*)phw;
int err = 0;
WAN_ASSERT(hw == NULL);
SDLA_MAGIC(hw);
WAN_ASSERT(hw->hwcard == NULL);
card = hw->hwcard;
if (addr + len > hw->memory) /* verify arguments */
return (EINVAL);
switch (card->type) {
case SDLA_AFT:
sdla_peek_by_4(hw, addr, buf, len);
break;
default:
log(LOG_INFO, "%s: Invalid card type 0x%X\n",
__FUNCTION__,card->type);
err = (EINVAL);
break;
}
return (err);
}
/*
* Read data from adapter's memory to a data buffer in 4-byte chunks.
* Note that we ensure that the SDLA memory address is on a 4-byte boundary
* before we begin moving the data in 4-byte chunks.
*/
static void
sdla_peek_by_4(sdlahw_t *hw, unsigned long offset, void *buf, unsigned int len)
{
/* byte copy data until we get to a 4-byte boundary */
while (len && (offset & 0x03)) {
sdla_bus_read_1(hw, offset++, (u_int8_t*)buf);
((u_int8_t *)buf)++;
len--;
}
/* copy data in 4-byte chunks */
while (len >= 4) {
sdla_bus_read_4(hw, offset, (u_int32_t*)buf);
(u_int8_t*)buf += 4;
offset += 4;
len -= 4;
}
/* byte copy any remaining data */
while (len) {
sdla_bus_read_1(hw, offset++, (u_int8_t*)buf);
((u_int8_t *)buf)++;
len--;
}
}
/*
* Write Absolute Adapter Memory.
* Transfer data from data buffer to adapter's memory.
*
* Note:
* Care should be taken when crossing dual-port memory window boundary.
* This function is not atomic, so caller must disable interrupt if
* interrupt routines are accessing adapter shared memory.
*/
int
sdla_poke(void *phw, unsigned long addr, void *buf, unsigned len)
{
sdlahw_card_t* card = NULL;
sdlahw_t* hw = (sdlahw_t*)phw;
int err = 0;
WAN_ASSERT(hw == NULL);
SDLA_MAGIC(hw);
WAN_ASSERT(hw->hwcard == NULL);
card = hw->hwcard;
if (addr + len > hw->memory) { /* verify arguments */
return (EINVAL);
}
switch (card->type) {
case SDLA_AFT:
sdla_poke_by_4(hw, addr, buf, len);
break;
default:
log(LOG_INFO, "%s: Invalid card type 0x%X\n",
__FUNCTION__,card->type);
err = (EINVAL);
break;
}
return (err);
}
/*
* Write from a data buffer to adapter's memory in 4-byte chunks.
* Note that we ensure that the SDLA memory address is on a 4-byte boundary
* before we begin moving the data in 4-byte chunks.
*/
static void
sdla_poke_by_4(sdlahw_t *hw, unsigned long offset, void *buf, unsigned int len)
{
/* byte copy data until we get to a 4-byte boundary */
while (len && (offset & 0x03)) {
sdla_bus_write_1(hw, offset++, *(char *)buf);
((char *)buf) ++;
len --;
}
/* copy data in 4-byte chunks */
while (len >= 4) {
sdla_bus_write_4(hw, offset, *(unsigned long *)buf);
offset += 4;
(char*)buf += 4;
len -= 4;
}
/* byte copy any remaining data */
while (len) {
sdla_bus_write_1(hw, offset++, *(char *)buf);
((char *)buf) ++;
len --;
}
}
int
sdla_poke_byte(void *phw, unsigned long offset, u_int8_t value)
{
sdlahw_t *hw = (sdlahw_t*)phw;
SDLA_MAGIC(hw);
/* Sangoma ISA card sdla_bus_write_1(hw, offset, value); */
sdla_poke(hw, offset, (void*)&value, 1);
return (0);
}
int
sdla_set_bit(void *phw, unsigned long offset, u_int8_t value)
{
sdlahw_t *hw = (sdlahw_t*)phw;
u_int8_t tmp;
SDLA_MAGIC(hw);
/* Sangoma ISA card -> sdla_bus_read_1(hw, offset, &tmp); */
sdla_peek(hw, offset, (void*)&tmp, 1);
tmp |= value;
/* Sangoma ISA card -> sdla_bus_write_1(hw, offset, tmp); */
sdla_poke(hw, offset, (void*)&tmp, 1);
return (0);
}
int
sdla_clear_bit(void *phw, unsigned long offset, u_int8_t value)
{
sdlahw_t *hw = (sdlahw_t*)phw;
u_int8_t tmp;
SDLA_MAGIC(hw);
/* Sangoma ISA card -> sdla_bus_read_1(hw, offset, &tmp); */
sdla_peek(hw, offset, (void*)&tmp, 1);
tmp &= ~value;
/* Sangoma ISA card -> sdla_bus_write_1(hw, offset, tmp); */
sdla_poke(hw, offset, (void*)&tmp, 1);
return (0);
}
/*
* Find the AFT HDLC PCI adapter in the PCI bus.
* Return the number of AFT adapters found (0 if no adapter found).
*/
static int
sdla_detect_aft(sdlahw_t *hw)
{
sdlahw_card_t *card;
u_int16_t ut_u16;
WAN_ASSERT(hw == NULL);
WAN_ASSERT(hw->hwcard == NULL);
card = hw->hwcard;
sdla_pci_read_config_dword(hw,
(hw->cpu_no == SDLA_CPU_A) ? PCI_IO_BASE_DWORD :
PCI_MEM_BASE0_DWORD, (u_int32_t*)&hw->mem_base_addr);
if (!hw->mem_base_addr) {
if (hw->cpu_no == SDLA_CPU_B) {
printf("%s: No PCI memory allocated for CPU #B\n",
hw->devname);
} else {
printf("%s: No PCI memory allocated to card\n",
hw->devname);
}
return (EINVAL);
}
#ifdef DEBUG
log(LOG_INFO, "%s: AFT PCI memory at 0x%lX\n",
hw->devname, (unsigned long)hw->mem_base_addr);
#endif /* DEBUG */
sdla_pci_read_config_byte(hw, PCI_INTLINE, (u_int8_t*)&hw->irq);
if (hw->irq == PCI_IRQ_NOT_ALLOCATED) {
printf("%s: IRQ not allocated to AFT adapter\n", hw->devname);
return (EINVAL);
}
#ifdef DEBUG
log(LOG_INFO, "%s: IRQ %d allocated to the AFT PCI card\n",
hw->devname, hw->irq);
#endif /* DEBUG */
hw->memory=XILINX_PCI_MEM_SIZE;
/* Map the physical PCI memory to virtual memory */
bus_space_map(hw->hwcard->memt, hw->mem_base_addr, XILINX_PCI_MEM_SIZE,
0, &hw->dpmbase);
if (!hw->dpmbase) {
printf("%s: couldn't map memory\n", hw->devname);
return (EINVAL);
}
hw->status |= SDLA_MEM_MAPPED;
/* Enable master operation on PCI and enable bar0 memory */
sdla_pci_read_config_word(hw, XILINX_PCI_CMD_REG, &ut_u16);
ut_u16 |=0x06;
sdla_pci_write_config_word(hw, XILINX_PCI_CMD_REG, ut_u16);
/* Set PCI Latency of 0xFF*/
sdla_pci_write_config_dword(hw, XILINX_PCI_LATENCY_REG,
XILINX_PCI_LATENCY);
return (0);
}
/*
* Detect adapter type.
*/
static int
sdla_detect(sdlahw_t *hw)
{
sdlahw_card_t *card = NULL;
int err = 0;
WAN_ASSERT(hw == NULL);
WAN_ASSERT(hw->hwcard == NULL);
card = hw->hwcard;
switch (card->type) {
case SDLA_AFT:
err = sdla_detect_aft(hw);
break;
}
if (err)
sdla_down(hw);
return (err);
}
int
sdla_is_te1(void *phw)
{
sdlahw_card_t *hwcard = NULL;
sdlahw_t *hw = (sdlahw_t*)phw;
WAN_ASSERT(hw == NULL);
SDLA_MAGIC(hw);
WAN_ASSERT(hw->hwcard == NULL);
hwcard = hw->hwcard;
switch (hwcard->atype) {
case S5144_ADPTR_1_CPU_T1E1:
case S5147_ADPTR_2_CPU_T1E1:
case S5148_ADPTR_1_CPU_T1E1:
case A101_ADPTR_1TE1:
case A101_ADPTR_2TE1:
return (1);
}
return (0);
}
int
sdla_check_mismatch(void *phw, unsigned char media)
{
sdlahw_card_t *hwcard = NULL;
sdlahw_t *hw = (sdlahw_t*)phw;
WAN_ASSERT(hw == NULL);
SDLA_MAGIC(hw);
WAN_ASSERT(hw->hwcard == NULL);
hwcard = hw->hwcard;
if (media == WAN_MEDIA_T1 ||
media == WAN_MEDIA_E1) {
if (hwcard->atype != S5144_ADPTR_1_CPU_T1E1 &&
hwcard->atype != S5147_ADPTR_2_CPU_T1E1 &&
hwcard->atype != S5148_ADPTR_1_CPU_T1E1) {
log(LOG_INFO, "%s: Error: Card type mismatch: "
"User=T1/E1 Actual=%s\n", hw->devname,
SDLA_ADPTR_DECODE(hwcard->atype));
return (EIO);
}
hwcard->atype = S5144_ADPTR_1_CPU_T1E1;
} else if (media == WAN_MEDIA_56K) {
if (hwcard->atype != S5145_ADPTR_1_CPU_56K) {
log(LOG_INFO, "%s: Error: Card type mismatch: "
"User=56K Actual=%s\n", hw->devname,
SDLA_ADPTR_DECODE(hwcard->atype));
return (EIO);
}
} else {
if (hwcard->atype == S5145_ADPTR_1_CPU_56K ||
hwcard->atype == S5144_ADPTR_1_CPU_T1E1 ||
hwcard->atype == S5147_ADPTR_2_CPU_T1E1 ||
hwcard->atype == S5148_ADPTR_1_CPU_T1E1) {
log(LOG_INFO, "%s: Error: Card type mismatch: "
"User=S514(1/2/3) Actual=%s\n", hw->devname,
SDLA_ADPTR_DECODE(hwcard->atype));
return (EIO);
}
}
return (0);
}
int
sdla_getcfg(void *phw, int type, void *value)
{
sdlahw_t* hw = (sdlahw_t*)phw;
sdlahw_card_t *hwcard;
WAN_ASSERT(hw == NULL);
SDLA_MAGIC(hw);
WAN_ASSERT(hw->hwcard == NULL);
hwcard = hw->hwcard;
switch (type) {
case SDLA_CARDTYPE:
*(u_int16_t*)value = hwcard->type;
break;
case SDLA_MEMBASE:
*(bus_space_handle_t*)value = hw->dpmbase;
break;
case SDLA_MEMEND:
*(u_int32_t*)value = ((unsigned long)hw->dpmbase +
hw->dpmsize - 1);
break;
case SDLA_MEMSIZE:
*(u_int16_t*)value = hw->dpmsize;
break;
case SDLA_MEMORY:
*(u_int32_t*)value = hw->memory;
break;
case SDLA_IRQ:
*(u_int16_t*)value = hw->irq;
break;
case SDLA_ADAPTERTYPE:
*(u_int16_t*)value = hwcard->atype;
break;
case SDLA_CPU:
*(u_int16_t*)value = hw->cpu_no;
break;
case SDLA_SLOT:
*(u_int16_t*)value = hwcard->slot_no;
break;
case SDLA_BUS:
*(u_int16_t*)value = hwcard->bus_no;
break;
case SDLA_DMATAG:
*(bus_dma_tag_t*)value = hwcard->pa.pa_dmat;
break;
case SDLA_PCIEXTRAVER:
*(u_int8_t*)value = hwcard->pci_extra_ver;
break;
case SDLA_BASEADDR:
*(u_int32_t*)value = hw->mem_base_addr;
break;
}
return (0);
}
int
sdla_get_hwcard(void *phw, void **phwcard)
{
sdlahw_t *hw = (sdlahw_t*)phw;
WAN_ASSERT(hw == NULL);
SDLA_MAGIC(hw);
*phwcard = hw->hwcard;
return (0);
}
int
sdla_get_hwprobe(void *phw, void **str)
{
sdlahw_t *hw = (sdlahw_t*)phw;
WAN_ASSERT(hw == NULL);
SDLA_MAGIC(hw);
if (hw->hwprobe)
*str = hw->hwprobe->hw_info;
return (0);
}
int
sdla_bus_write_1(void *phw, unsigned int offset, u_int8_t value)
{
sdlahw_t *hw = (sdlahw_t*)phw;
WAN_ASSERT(hw == NULL);
SDLA_MAGIC(hw);
if (!(hw->status & SDLA_MEM_MAPPED))
return (0);
bus_space_write_1(hw->hwcard->memt, hw->dpmbase, offset, value);
return (0);
}
int
sdla_bus_write_2(void *phw, unsigned int offset, u_int16_t value)
{
sdlahw_t *hw = (sdlahw_t*)phw;
WAN_ASSERT(hw == NULL);
SDLA_MAGIC(hw);
if (!(hw->status & SDLA_MEM_MAPPED))
return (0);
bus_space_write_2(hw->hwcard->memt, hw->dpmbase, offset, value);
return (0);
}
int
sdla_bus_write_4(void *phw, unsigned int offset, u_int32_t value)
{
sdlahw_t *hw = (sdlahw_t*)phw;
WAN_ASSERT(hw == NULL);
SDLA_MAGIC(hw);
if (!(hw->status & SDLA_MEM_MAPPED))
return (0);
bus_space_write_4(hw->hwcard->memt, hw->dpmbase, offset, value);
return (0);
}
int
sdla_bus_read_1(void *phw, unsigned int offset, u_int8_t *value)
{
sdlahw_t *hw = (sdlahw_t*)phw;
WAN_ASSERT2(hw == NULL, 0);
SDLA_MAGIC(hw);
if (!(hw->status & SDLA_MEM_MAPPED))
return (0);
*value = bus_space_read_1(hw->hwcard->memt, hw->dpmbase, offset);
return (0);
}
int
sdla_bus_read_2(void *phw, unsigned int offset, u_int16_t *value)
{
sdlahw_t *hw = (sdlahw_t*)phw;
WAN_ASSERT2(hw == NULL, 0);
SDLA_MAGIC(hw);
if (!(hw->status & SDLA_MEM_MAPPED))
return (0);
*value = bus_space_read_2(hw->hwcard->memt, hw->dpmbase, offset);
return (0);
}
int
sdla_bus_read_4(void *phw, unsigned int offset, u_int32_t *value)
{
sdlahw_t *hw = (sdlahw_t*)phw;
WAN_ASSERT2(hw == NULL, 0);
WAN_ASSERT2(hw->dpmbase == 0, 0);
SDLA_MAGIC(hw);
if (!(hw->status & SDLA_MEM_MAPPED))
return (0);
*value = bus_space_read_4(hw->hwcard->memt, hw->dpmbase, offset);
return (0);
}
static int
sdla_pci_read_config_dword(void *phw, int reg, u_int32_t *value)
{
sdlahw_t *hw = (sdlahw_t*)phw;
sdlahw_card_t *hwcard;
WAN_ASSERT(hw == NULL);
SDLA_MAGIC(hw);
WAN_ASSERT(hw->hwcard == NULL);
hwcard = hw->hwcard;
*value = pci_conf_read(hwcard->pa.pa_pc, hwcard->pa.pa_tag, reg);
return (0);
}
static int
sdla_pci_read_config_word(void *phw, int reg, u_int16_t *value)
{
sdlahw_t *hw = (sdlahw_t*)phw;
sdlahw_card_t *hwcard;
u_int32_t tmp = 0x00;
WAN_ASSERT(hw == NULL);
SDLA_MAGIC(hw);
WAN_ASSERT(hw->hwcard == NULL);
hwcard = hw->hwcard;
tmp = pci_conf_read(hwcard->pa.pa_pc, hwcard->pa.pa_tag, reg);
*value = (u_int16_t)((tmp >> 16) & 0xFFFF);
return (0);
}
static int
sdla_pci_read_config_byte(void *phw, int reg, u_int8_t *value)
{
sdlahw_t *hw = (sdlahw_t*)phw;
sdlahw_card_t *hwcard;
u_int32_t tmp = 0x00;
WAN_ASSERT(hw == NULL);
SDLA_MAGIC(hw);
WAN_ASSERT(hw->hwcard == NULL);
hwcard = hw->hwcard;
tmp = pci_conf_read(hwcard->pa.pa_pc, hwcard->pa.pa_tag, reg);
*value = (u_int8_t)(tmp & 0xFF);
return (0);
}
static int
sdla_pci_write_config_dword(void *phw, int reg, u_int32_t value)
{
sdlahw_t *hw = (sdlahw_t*)phw;
sdlahw_card_t *card;
WAN_ASSERT(hw == NULL);
SDLA_MAGIC(hw);
WAN_ASSERT(hw->hwcard == NULL);
card = hw->hwcard;
pci_conf_write(card->pa.pa_pc, card->pa.pa_tag, reg, value);
return (0);
}
static int
sdla_pci_write_config_word(void *phw, int reg, u_int16_t value)
{
sdlahw_t *hw = (sdlahw_t*)phw;
sdlahw_card_t *card;
WAN_ASSERT(hw == NULL);
SDLA_MAGIC(hw);
WAN_ASSERT(hw->hwcard == NULL);
card = hw->hwcard;
pci_conf_write(card->pa.pa_pc, card->pa.pa_tag, reg, value);
return (0);
}