mirror of
git://projects.qi-hardware.com/openwrt-xburst.git
synced 2025-04-21 12:27:27 +03:00
add all source code from linksys/broadcom which is free, to cvs for better maintainence inside
openwrt. this gives us the ability to better support different hardware models, without changing any external tar-balls. only et.o and wl.o is missing and is fetched from my webserver. git-svn-id: svn://svn.openwrt.org/openwrt/trunk/openwrt@379 3c298f89-4303-0410-b956-a3cf2f4a3e73
This commit is contained in:
9
package/linux/kernel-source/drivers/net/diag/Makefile
Normal file
9
package/linux/kernel-source/drivers/net/diag/Makefile
Normal file
@@ -0,0 +1,9 @@
|
||||
O_TARGET := diag.o
|
||||
|
||||
MAC_OBJS := diag_led.o
|
||||
|
||||
export-objs :=
|
||||
obj-y := $(MAC_OBJS)
|
||||
obj-m := $(O_TARGET)
|
||||
|
||||
include $(TOPDIR)/Rules.make
|
||||
210
package/linux/kernel-source/drivers/net/diag/diag_led.c
Normal file
210
package/linux/kernel-source/drivers/net/diag/diag_led.c
Normal file
@@ -0,0 +1,210 @@
|
||||
// replacement diag module
|
||||
// (c) 2004 openwrt
|
||||
// mbm at alt dot org
|
||||
//
|
||||
// initial release 2004/03/28
|
||||
//
|
||||
// 2004/08/26 asus & buffalo support added
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/sysctl.h>
|
||||
#include <asm/io.h>
|
||||
#include <typedefs.h>
|
||||
#include <bcm4710.h>
|
||||
#include <sbutils.h>
|
||||
|
||||
extern char * nvram_get(const char *name);
|
||||
static void *sbh;
|
||||
|
||||
// v2.x - - - - -
|
||||
#define DIAG_GPIO (1<<1)
|
||||
#define DMZ_GPIO (1<<7)
|
||||
|
||||
static void set_gpio(uint32 mask, uint32 value) {
|
||||
sb_gpiocontrol(sbh,mask,0);
|
||||
sb_gpioouten(sbh,mask,mask);
|
||||
sb_gpioout(sbh,mask,value);
|
||||
}
|
||||
|
||||
static void v2_set_diag(u8 state) {
|
||||
set_gpio(DIAG_GPIO,state);
|
||||
}
|
||||
static void v2_set_dmz(u8 state) {
|
||||
set_gpio(DMZ_GPIO,state);
|
||||
}
|
||||
|
||||
// v1.x - - - - -
|
||||
#define LED_DIAG 0x13
|
||||
#define LED_DMZ 0x12
|
||||
|
||||
static void v1_set_diag(u8 state) {
|
||||
if (!state) {
|
||||
*(volatile u8*)(KSEG1ADDR(BCM4710_EUART)+LED_DIAG)=0xFF;
|
||||
} else {
|
||||
*(volatile u8*)(KSEG1ADDR(BCM4710_EUART)+LED_DIAG);
|
||||
}
|
||||
}
|
||||
static void v1_set_dmz(u8 state) {
|
||||
if (!state) {
|
||||
*(volatile u8*)(KSEG1ADDR(BCM4710_EUART)+LED_DMZ)=0xFF;
|
||||
} else {
|
||||
*(volatile u8*)(KSEG1ADDR(BCM4710_EUART)+LED_DMZ);
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - -
|
||||
static void ignore(u8 ignored) {};
|
||||
|
||||
// - - - - -
|
||||
#define BIT_DMZ 0x01
|
||||
#define BIT_DIAG 0x04
|
||||
|
||||
void (*set_diag)(u8 state);
|
||||
void (*set_dmz)(u8 state);
|
||||
|
||||
static unsigned int diag = 0;
|
||||
|
||||
static void diag_change()
|
||||
{
|
||||
//printk(KERN_INFO "led -> %02x\n",diag);
|
||||
|
||||
set_diag(0xFF); // off
|
||||
set_dmz(0xFF); // off
|
||||
|
||||
if(diag & BIT_DIAG)
|
||||
set_diag(0x00); // on
|
||||
if(diag & BIT_DMZ)
|
||||
set_dmz(0x00); // on
|
||||
}
|
||||
|
||||
static int proc_diag(ctl_table *table, int write, struct file *filp,
|
||||
void *buffer, size_t *lenp)
|
||||
{
|
||||
int r;
|
||||
r = proc_dointvec(table, write, filp, buffer, lenp);
|
||||
if (write && !r) {
|
||||
diag_change();
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
// - - - - -
|
||||
static unsigned char reset_gpio = 0;
|
||||
static unsigned char reset_polarity = 0;
|
||||
static unsigned int reset = 0;
|
||||
|
||||
static int proc_reset(ctl_table *table, int write, struct file *filp,
|
||||
void *buffer, size_t *lenp)
|
||||
{
|
||||
|
||||
if (reset_gpio) {
|
||||
sb_gpiocontrol(sbh,reset_gpio,reset_gpio);
|
||||
sb_gpioouten(sbh,reset_gpio,0);
|
||||
reset=!(sb_gpioin(sbh)&reset_gpio);
|
||||
|
||||
if (reset_polarity) reset=!reset;
|
||||
} else {
|
||||
reset=0;
|
||||
}
|
||||
|
||||
return proc_dointvec(table, write, filp, buffer, lenp);
|
||||
}
|
||||
|
||||
// - - - - -
|
||||
static struct ctl_table_header *diag_sysctl_header;
|
||||
|
||||
static ctl_table sys_diag[] = {
|
||||
{
|
||||
ctl_name: 2000,
|
||||
procname: "diag",
|
||||
data: &diag,
|
||||
maxlen: sizeof(diag),
|
||||
mode: 0644,
|
||||
proc_handler: proc_diag
|
||||
},
|
||||
{
|
||||
ctl_name: 2001,
|
||||
procname: "reset",
|
||||
data: &reset,
|
||||
maxlen: sizeof(reset),
|
||||
mode: 0444,
|
||||
proc_handler: proc_reset
|
||||
},
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
static int __init diag_init()
|
||||
{
|
||||
char *buf;
|
||||
u32 board_type;
|
||||
sbh = sb_kattach();
|
||||
sb_gpiosetcore(sbh);
|
||||
|
||||
board_type = sb_boardtype(sbh);
|
||||
printk(KERN_INFO "diag boardtype: %08x\n",board_type);
|
||||
|
||||
set_diag=ignore;
|
||||
set_dmz=ignore;
|
||||
|
||||
if ((board_type & 0xf00) == 0x400) {
|
||||
board_type=1;
|
||||
buf=nvram_get("boardtype")?:"";
|
||||
if (!strcmp(buf,"bcm94710dev")) {
|
||||
buf=nvram_get("boardnum")?:"";
|
||||
if (!strcmp(buf,"42")) {
|
||||
// wrt54g v1.x
|
||||
set_diag=v1_set_diag;
|
||||
set_dmz=v1_set_dmz;
|
||||
reset_gpio=(1<<6);
|
||||
reset_polarity=0;
|
||||
} else if (!strcmp(buf,"asusX")) {
|
||||
//asus wl-500g
|
||||
//no leds
|
||||
reset_gpio=(1<<6);
|
||||
reset_polarity=1;
|
||||
}
|
||||
} else if (!strcmp(buf,"bcm94710ap")) {
|
||||
buf=nvram_get("boardnum")?:"";
|
||||
if (!strcmp(buf,"42")) {
|
||||
// buffalo
|
||||
set_dmz=v2_set_dmz;
|
||||
reset_gpio=(1<<4);
|
||||
reset_polarity=1;
|
||||
} else if (!strcmp(buf,"44")) {
|
||||
//dell truemobile
|
||||
set_dmz=v2_set_dmz;
|
||||
reset_gpio=(1<<0);
|
||||
reset_polarity=0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
board_type=2;
|
||||
set_diag=v2_set_diag;
|
||||
set_dmz=v2_set_dmz;
|
||||
reset_gpio=(1<<6);
|
||||
reset_polarity=0;
|
||||
buf=nvram_get("boardnum")?:"";
|
||||
if (!strcmp(buf,"44")) {
|
||||
set_diag=ignore;
|
||||
set_dmz=ignore;
|
||||
reset_gpio=(1<<5);
|
||||
reset_polarity=0;
|
||||
}
|
||||
}
|
||||
printk(KERN_INFO "using v%d hardware\n",board_type);
|
||||
|
||||
diag_sysctl_header = register_sysctl_table(sys_diag, 0);
|
||||
diag_change();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit diag_exit()
|
||||
{
|
||||
unregister_sysctl_table(diag_sysctl_header);
|
||||
}
|
||||
|
||||
module_init(diag_init);
|
||||
module_exit(diag_exit);
|
||||
34
package/linux/kernel-source/drivers/net/et/Makefile
Normal file
34
package/linux/kernel-source/drivers/net/et/Makefile
Normal file
@@ -0,0 +1,34 @@
|
||||
#
|
||||
# Makefile for the Broadcom et driver
|
||||
#
|
||||
# Copyright 2004, Broadcom Corporation
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
|
||||
# KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
|
||||
# SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
# FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
|
||||
#
|
||||
# $Id$
|
||||
#
|
||||
|
||||
O_TARGET := et.o
|
||||
|
||||
ET_OBJS := et_linux.o etc.o
|
||||
|
||||
ifeq ($(CONFIG_ET_47XX),y)
|
||||
ET_OBJS += etc47xx.o etc_robo.o etc_adm.o
|
||||
EXTRA_CFLAGS += -DBCM47XX_CHOPS
|
||||
endif
|
||||
ifeq ($(CONFIG_ET_4413),y)
|
||||
ET_OBJS += etc4413.o
|
||||
EXTRA_CFLAGS += -DBCM4413_CHOPS
|
||||
endif
|
||||
|
||||
export-objs :=
|
||||
obj-y := $(ET_OBJS)
|
||||
obj-m := $(O_TARGET)
|
||||
|
||||
EXTRA_CFLAGS += -DDMA
|
||||
|
||||
include $(TOPDIR)/Rules.make
|
||||
35
package/linux/kernel-source/drivers/net/hnd/Config.in
Normal file
35
package/linux/kernel-source/drivers/net/hnd/Config.in
Normal file
@@ -0,0 +1,35 @@
|
||||
#
|
||||
# Broadcom Home Networking Division (HND) driver configuration
|
||||
#
|
||||
# Copyright 2004, Broadcom Corporation
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
|
||||
# KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
|
||||
# SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
# FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
|
||||
#
|
||||
|
||||
mainmenu_option next_comment
|
||||
comment 'Broadcom HND network devices'
|
||||
tristate 'Broadcom HND network device support' CONFIG_HND $CONFIG_PCI
|
||||
if [ "$CONFIG_HND" != "n" ]; then
|
||||
dep_tristate ' Broadcom InsideLine HPNA support' CONFIG_IL $CONFIG_HND
|
||||
if [ "$CONFIG_IL" != "n" ]; then
|
||||
bool ' Broadcom BCM42xx support' CONFIG_IL_42XX
|
||||
bool ' Broadcom BCM47xx support' CONFIG_IL_47XX
|
||||
int ' LARQ buffer allocation (0 = tiny, 2 = huge)' CONFIG_LARQ_BUF 0
|
||||
fi
|
||||
dep_tristate ' Broadcom 10/100 Ethernet support' CONFIG_ET $CONFIG_HND
|
||||
if [ "$CONFIG_ET" != "n" ]; then
|
||||
bool ' Broadcom BCM4413 support' CONFIG_ET_4413
|
||||
bool ' Broadcom BCM47xx support' CONFIG_ET_47XX
|
||||
fi
|
||||
dep_tristate ' Broadcom BCM43xx 802.11 Wireless support' CONFIG_WL $CONFIG_HND
|
||||
if [ "$CONFIG_WL" != "n" ]; then
|
||||
bool ' Access Point Mode Supported' CONFIG_WL_AP
|
||||
bool ' STA Mode Supported' CONFIG_WL_STA
|
||||
bool ' OID Interface Supported' CONFIG_WL_OID
|
||||
fi
|
||||
fi
|
||||
endmenu
|
||||
30
package/linux/kernel-source/drivers/net/hnd/Makefile
Normal file
30
package/linux/kernel-source/drivers/net/hnd/Makefile
Normal file
@@ -0,0 +1,30 @@
|
||||
#
|
||||
# Makefile for Broadcom Home Networking Division (HND) shared driver code
|
||||
#
|
||||
# Copyright 2004, Broadcom Corporation
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
|
||||
# KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
|
||||
# SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
# FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
|
||||
#
|
||||
# $Id$
|
||||
#
|
||||
|
||||
O_TARGET := hnd.o
|
||||
|
||||
HND_OBJS := bcmutils.o hnddma.o linux_osl.o sbutils.o bcmsrom.o
|
||||
|
||||
ifneq ($(CONFIG_BCM947XX),y)
|
||||
HND_OBJS += nvramstubs.o
|
||||
endif
|
||||
|
||||
export-objs := shared_ksyms.o
|
||||
obj-y := shared_ksyms.o $(HND_OBJS)
|
||||
obj-m := $(O_TARGET)
|
||||
|
||||
include $(TOPDIR)/Rules.make
|
||||
|
||||
shared_ksyms.c: shared_ksyms.sh $(HND_OBJS)
|
||||
sh -e $< $(HND_OBJS) > $@
|
||||
711
package/linux/kernel-source/drivers/net/hnd/bcmsrom.c
Normal file
711
package/linux/kernel-source/drivers/net/hnd/bcmsrom.c
Normal file
@@ -0,0 +1,711 @@
|
||||
/*
|
||||
* Misc useful routines to access NIC SROM
|
||||
*
|
||||
* Copyright 2004, Broadcom Corporation
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
|
||||
* KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
|
||||
* SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#include <typedefs.h>
|
||||
#include <osl.h>
|
||||
#include <bcmutils.h>
|
||||
#include <bcmsrom.h>
|
||||
#include <bcmdevs.h>
|
||||
#include <bcmendian.h>
|
||||
#include <sbpcmcia.h>
|
||||
#include <pcicfg.h>
|
||||
#include <sbutils.h>
|
||||
|
||||
#include <proto/ethernet.h> /* for sprom content groking */
|
||||
|
||||
#define VARS_MAX 4096 /* should be reduced */
|
||||
|
||||
static int initvars_srom_pci(void *curmap, char **vars, int *count);
|
||||
static int initvars_cis_pcmcia(void *sbh, void *curmap, void *osh, char **vars, int *count);
|
||||
static int sprom_cmd_pcmcia(void *osh, uint8 cmd);
|
||||
static int sprom_read_pcmcia(void *osh, uint16 addr, uint16 *data);
|
||||
static int sprom_write_pcmcia(void *osh, uint16 addr, uint16 data);
|
||||
static int sprom_read_pci(uint16 *sprom, uint byteoff, uint16 *buf, uint nbytes, bool check_crc);
|
||||
|
||||
/*
|
||||
* Initialize the vars from the right source for this platform.
|
||||
* Return 0 on success, nonzero on error.
|
||||
*/
|
||||
int
|
||||
srom_var_init(void *sbh, uint bus, void *curmap, void *osh, char **vars, int *count)
|
||||
{
|
||||
if (vars == NULL)
|
||||
return (0);
|
||||
|
||||
switch (bus) {
|
||||
case SB_BUS:
|
||||
/* These two could be asserts ... */
|
||||
*vars = NULL;
|
||||
*count = 0;
|
||||
return(0);
|
||||
|
||||
case PCI_BUS:
|
||||
ASSERT(curmap); /* can not be NULL */
|
||||
return(initvars_srom_pci(curmap, vars, count));
|
||||
|
||||
case PCMCIA_BUS:
|
||||
return(initvars_cis_pcmcia(sbh, curmap, osh, vars, count));
|
||||
|
||||
|
||||
default:
|
||||
ASSERT(0);
|
||||
}
|
||||
return (-1);
|
||||
}
|
||||
|
||||
|
||||
/* support only 16-bit word read from srom */
|
||||
int
|
||||
srom_read(uint bus, void *curmap, void *osh, uint byteoff, uint nbytes, uint16 *buf)
|
||||
{
|
||||
void *srom;
|
||||
uint i, off, nw;
|
||||
|
||||
/* check input - 16-bit access only */
|
||||
if (byteoff & 1 || nbytes & 1 || (byteoff + nbytes) > (SPROM_SIZE * 2))
|
||||
return 1;
|
||||
|
||||
if (bus == PCI_BUS) {
|
||||
if (!curmap)
|
||||
return 1;
|
||||
srom = (void *)((uint)curmap + PCI_BAR0_SPROM_OFFSET);
|
||||
if (sprom_read_pci(srom, byteoff, buf, nbytes, FALSE))
|
||||
return 1;
|
||||
} else if (bus == PCMCIA_BUS) {
|
||||
off = byteoff / 2;
|
||||
nw = nbytes / 2;
|
||||
for (i = 0; i < nw; i++) {
|
||||
if (sprom_read_pcmcia(osh, (uint16)(off + i), (uint16*)(buf + i)))
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* support only 16-bit word write into srom */
|
||||
int
|
||||
srom_write(uint bus, void *curmap, void *osh, uint byteoff, uint nbytes, uint16 *buf)
|
||||
{
|
||||
uint16 *srom;
|
||||
uint i, off, nw, crc_range;
|
||||
uint16 image[SPROM_SIZE], *p;
|
||||
uint8 crc;
|
||||
volatile uint32 val32;
|
||||
|
||||
/* check input - 16-bit access only */
|
||||
if (byteoff & 1 || nbytes & 1 || (byteoff + nbytes) > (SPROM_SIZE * 2))
|
||||
return 1;
|
||||
|
||||
crc_range = ((bus == PCMCIA_BUS) ? SPROM_SIZE : SPROM_CRC_RANGE) * 2;
|
||||
|
||||
/* if changes made inside crc cover range */
|
||||
if (byteoff < crc_range) {
|
||||
nw = (((byteoff + nbytes) > crc_range) ? byteoff + nbytes : crc_range) / 2;
|
||||
/* read data including entire first 64 words from srom */
|
||||
if (srom_read(bus, curmap, osh, 0, nw * 2, image))
|
||||
return 1;
|
||||
/* make changes */
|
||||
bcopy((void*)buf, (void*)&image[byteoff / 2], nbytes);
|
||||
/* calculate crc */
|
||||
htol16_buf(image, crc_range);
|
||||
crc = ~crc8((uint8 *)image, crc_range - 1, CRC8_INIT_VALUE);
|
||||
ltoh16_buf(image, crc_range);
|
||||
image[(crc_range / 2) - 1] = (crc << 8) | (image[(crc_range / 2) - 1] & 0xff);
|
||||
p = image;
|
||||
off = 0;
|
||||
} else {
|
||||
p = buf;
|
||||
off = byteoff / 2;
|
||||
nw = nbytes / 2;
|
||||
}
|
||||
|
||||
if (bus == PCI_BUS) {
|
||||
srom = (uint16*)((uint)curmap + PCI_BAR0_SPROM_OFFSET);
|
||||
/* enable writes to the SPROM */
|
||||
val32 = OSL_PCI_READ_CONFIG(osh, PCI_SPROM_CONTROL, sizeof(uint32));
|
||||
val32 |= SPROM_WRITEEN;
|
||||
OSL_PCI_WRITE_CONFIG(osh, PCI_SPROM_CONTROL, sizeof(uint32), val32);
|
||||
bcm_mdelay(500);
|
||||
/* write srom */
|
||||
for (i = 0; i < nw; i++) {
|
||||
W_REG(&srom[off + i], p[i]);
|
||||
bcm_mdelay(20);
|
||||
}
|
||||
/* disable writes to the SPROM */
|
||||
OSL_PCI_WRITE_CONFIG(osh, PCI_SPROM_CONTROL, sizeof(uint32), val32 & ~SPROM_WRITEEN);
|
||||
} else if (bus == PCMCIA_BUS) {
|
||||
/* enable writes to the SPROM */
|
||||
if (sprom_cmd_pcmcia(osh, SROM_WEN))
|
||||
return 1;
|
||||
bcm_mdelay(500);
|
||||
/* write srom */
|
||||
for (i = 0; i < nw; i++) {
|
||||
sprom_write_pcmcia(osh, (uint16)(off + i), p[i]);
|
||||
bcm_mdelay(20);
|
||||
}
|
||||
/* disable writes to the SPROM */
|
||||
if (sprom_cmd_pcmcia(osh, SROM_WDS))
|
||||
return 1;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
|
||||
bcm_mdelay(500);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
srom_parsecis(uint8 *cis, char **vars, int *count)
|
||||
{
|
||||
char eabuf[32];
|
||||
char *vp, *base;
|
||||
uint8 tup, tlen, sromrev = 1;
|
||||
int i, j;
|
||||
uint varsize;
|
||||
bool ag_init = FALSE;
|
||||
uint16 w;
|
||||
|
||||
ASSERT(vars);
|
||||
ASSERT(count);
|
||||
|
||||
base = vp = MALLOC(VARS_MAX);
|
||||
ASSERT(vp);
|
||||
|
||||
i = 0;
|
||||
do {
|
||||
tup = cis[i++];
|
||||
tlen = cis[i++];
|
||||
if ((i + tlen) >= CIS_SIZE)
|
||||
break;
|
||||
|
||||
switch (tup) {
|
||||
case CISTPL_MANFID:
|
||||
vp += sprintf(vp, "manfid=%d", (cis[i + 1] << 8) + cis[i]);
|
||||
vp++;
|
||||
vp += sprintf(vp, "prodid=%d", (cis[i + 3] << 8) + cis[i + 2]);
|
||||
vp++;
|
||||
break;
|
||||
|
||||
case CISTPL_FUNCE:
|
||||
if (cis[i] == LAN_NID) {
|
||||
ASSERT(cis[i + 1] == ETHER_ADDR_LEN);
|
||||
bcm_ether_ntoa((uchar*)&cis[i + 2], eabuf);
|
||||
vp += sprintf(vp, "il0macaddr=%s", eabuf);
|
||||
vp++;
|
||||
}
|
||||
break;
|
||||
|
||||
case CISTPL_CFTABLE:
|
||||
vp += sprintf(vp, "regwindowsz=%d", (cis[i + 7] << 8) | cis[i + 6]);
|
||||
vp++;
|
||||
break;
|
||||
|
||||
case CISTPL_BRCM_HNBU:
|
||||
switch (cis[i]) {
|
||||
case HNBU_CHIPID:
|
||||
vp += sprintf(vp, "vendid=%d", (cis[i + 2] << 8) + cis[i + 1]);
|
||||
vp++;
|
||||
vp += sprintf(vp, "devid=%d", (cis[i + 4] << 8) + cis[i + 3]);
|
||||
vp++;
|
||||
if (tlen == 7) {
|
||||
vp += sprintf(vp, "chiprev=%d", (cis[i + 6] << 8) + cis[i + 5]);
|
||||
vp++;
|
||||
}
|
||||
break;
|
||||
|
||||
case HNBU_BOARDREV:
|
||||
vp += sprintf(vp, "boardrev=%d", cis[i + 1]);
|
||||
vp++;
|
||||
break;
|
||||
|
||||
case HNBU_AA:
|
||||
vp += sprintf(vp, "aa0=%d", cis[i + 1]);
|
||||
vp++;
|
||||
break;
|
||||
|
||||
case HNBU_AG:
|
||||
vp += sprintf(vp, "ag0=%d", cis[i + 1]);
|
||||
vp++;
|
||||
ag_init = TRUE;
|
||||
break;
|
||||
|
||||
case HNBU_CC:
|
||||
vp += sprintf(vp, "cc=%d", cis[i + 1]);
|
||||
vp++;
|
||||
break;
|
||||
|
||||
case HNBU_PAPARMS:
|
||||
vp += sprintf(vp, "pa0maxpwr=%d", cis[i + tlen - 1]);
|
||||
vp++;
|
||||
if (tlen == 9) {
|
||||
/* New version */
|
||||
for (j = 0; j < 3; j++) {
|
||||
vp += sprintf(vp, "pa0b%d=%d", j,
|
||||
(cis[i + (j * 2) + 2] << 8) + cis[i + (j * 2) + 1]);
|
||||
vp++;
|
||||
}
|
||||
vp += sprintf(vp, "pa0itssit=%d", cis[i + 7]);
|
||||
vp++;
|
||||
}
|
||||
break;
|
||||
|
||||
case HNBU_OEM:
|
||||
vp += sprintf(vp, "oem=%02x%02x%02x%02x%02x%02x%02x%02x",
|
||||
cis[i + 1], cis[i + 2], cis[i + 3], cis[i + 4],
|
||||
cis[i + 5], cis[i + 6], cis[i + 7], cis[i + 8]);
|
||||
vp++;
|
||||
break;
|
||||
case HNBU_BOARDFLAGS:
|
||||
w = (cis[i + 2] << 8) + cis[i + 1];
|
||||
if (w == 0xffff) w = 0;
|
||||
vp += sprintf(vp, "boardflags=%d", w);
|
||||
vp++;
|
||||
break;
|
||||
case HNBU_LED:
|
||||
if (cis[i + 1] != 0xff) {
|
||||
vp += sprintf(vp, "wl0gpio0=%d", cis[i + 1]);
|
||||
vp++;
|
||||
}
|
||||
if (cis[i + 2] != 0xff) {
|
||||
vp += sprintf(vp, "wl0gpio1=%d", cis[i + 2]);
|
||||
vp++;
|
||||
}
|
||||
if (cis[i + 3] != 0xff) {
|
||||
vp += sprintf(vp, "wl0gpio2=%d", cis[i + 3]);
|
||||
vp++;
|
||||
}
|
||||
if (cis[i + 4] != 0xff) {
|
||||
vp += sprintf(vp, "wl0gpio3=%d", cis[i + 4]);
|
||||
vp++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
i += tlen;
|
||||
} while (tup != 0xff);
|
||||
|
||||
/* Set the srom version */
|
||||
vp += sprintf(vp, "sromrev=%d", sromrev);
|
||||
vp++;
|
||||
|
||||
/* For now just set boardflags2 to zero */
|
||||
vp += sprintf(vp, "boardflags2=0");
|
||||
vp++;
|
||||
|
||||
/* if there is no antenna gain field, set default */
|
||||
if (ag_init == FALSE) {
|
||||
vp += sprintf(vp, "ag0=%d", 0xff);
|
||||
vp++;
|
||||
}
|
||||
|
||||
/* final nullbyte terminator */
|
||||
*vp++ = '\0';
|
||||
varsize = (uint)vp - (uint)base;
|
||||
|
||||
ASSERT(varsize < VARS_MAX);
|
||||
|
||||
if (varsize == VARS_MAX) {
|
||||
*vars = base;
|
||||
} else {
|
||||
vp = MALLOC(varsize);
|
||||
ASSERT(vp);
|
||||
bcopy(base, vp, varsize);
|
||||
MFREE(base, VARS_MAX);
|
||||
*vars = vp;
|
||||
}
|
||||
*count = varsize;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
/* set PCMCIA sprom command register */
|
||||
static int
|
||||
sprom_cmd_pcmcia(void *osh, uint8 cmd)
|
||||
{
|
||||
uint8 status;
|
||||
uint wait_cnt = 1000;
|
||||
|
||||
/* write sprom command register */
|
||||
OSL_PCMCIA_WRITE_ATTR(osh, SROM_CS, &cmd, 1);
|
||||
|
||||
/* wait status */
|
||||
while (wait_cnt--) {
|
||||
OSL_PCMCIA_READ_ATTR(osh, SROM_CS, &status, 1);
|
||||
if (status & SROM_DONE)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* read a word from the PCMCIA srom */
|
||||
static int
|
||||
sprom_read_pcmcia(void *osh, uint16 addr, uint16 *data)
|
||||
{
|
||||
uint8 addr_l, addr_h, data_l, data_h;
|
||||
|
||||
addr_l = (uint8)((addr * 2) & 0xff);
|
||||
addr_h = (uint8)(((addr * 2) >> 8) & 0xff);
|
||||
|
||||
/* set address */
|
||||
OSL_PCMCIA_WRITE_ATTR(osh, SROM_ADDRH, &addr_h, 1);
|
||||
OSL_PCMCIA_WRITE_ATTR(osh, SROM_ADDRL, &addr_l, 1);
|
||||
|
||||
/* do read */
|
||||
if (sprom_cmd_pcmcia(osh, SROM_READ))
|
||||
return 1;
|
||||
|
||||
/* read data */
|
||||
OSL_PCMCIA_READ_ATTR(osh, SROM_DATAH, &data_h, 1);
|
||||
OSL_PCMCIA_READ_ATTR(osh, SROM_DATAL, &data_l, 1);
|
||||
|
||||
*data = (data_h << 8) | data_l;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* write a word to the PCMCIA srom */
|
||||
static int
|
||||
sprom_write_pcmcia(void *osh, uint16 addr, uint16 data)
|
||||
{
|
||||
uint8 addr_l, addr_h, data_l, data_h;
|
||||
|
||||
addr_l = (uint8)((addr * 2) & 0xff);
|
||||
addr_h = (uint8)(((addr * 2) >> 8) & 0xff);
|
||||
data_l = (uint8)(data & 0xff);
|
||||
data_h = (uint8)((data >> 8) & 0xff);
|
||||
|
||||
/* set address */
|
||||
OSL_PCMCIA_WRITE_ATTR(osh, SROM_ADDRH, &addr_h, 1);
|
||||
OSL_PCMCIA_WRITE_ATTR(osh, SROM_ADDRL, &addr_l, 1);
|
||||
|
||||
/* write data */
|
||||
OSL_PCMCIA_WRITE_ATTR(osh, SROM_DATAH, &data_h, 1);
|
||||
OSL_PCMCIA_WRITE_ATTR(osh, SROM_DATAL, &data_l, 1);
|
||||
|
||||
/* do write */
|
||||
return sprom_cmd_pcmcia(osh, SROM_WRITE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read in and validate sprom.
|
||||
* Return 0 on success, nonzero on error.
|
||||
*/
|
||||
static int
|
||||
sprom_read_pci(uint16 *sprom, uint byteoff, uint16 *buf, uint nbytes, bool check_crc)
|
||||
{
|
||||
int off, nw;
|
||||
uint8 chk8;
|
||||
int i;
|
||||
|
||||
off = byteoff / 2;
|
||||
nw = ROUNDUP(nbytes, 2) / 2;
|
||||
|
||||
/* read the sprom */
|
||||
for (i = 0; i < nw; i++)
|
||||
buf[i] = R_REG(&sprom[off + i]);
|
||||
|
||||
if (check_crc) {
|
||||
/* fixup the endianness so crc8 will pass */
|
||||
htol16_buf(buf, nw * 2);
|
||||
if ((chk8 = crc8((uchar*)buf, nbytes, CRC8_INIT_VALUE)) != CRC8_GOOD_VALUE)
|
||||
return (1);
|
||||
/* now correct the endianness of the byte array */
|
||||
ltoh16_buf(buf, nw * 2);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize nonvolatile variable table from sprom.
|
||||
* Return 0 on success, nonzero on error.
|
||||
*/
|
||||
|
||||
static int
|
||||
initvars_srom_pci(void *curmap, char **vars, int *count)
|
||||
{
|
||||
uint16 w, b[64];
|
||||
uint8 sromrev;
|
||||
struct ether_addr ea;
|
||||
char eabuf[32];
|
||||
uint32 bfl;
|
||||
int c, woff, i;
|
||||
char *vp, *base;
|
||||
|
||||
if (sprom_read_pci((void *)((uint)curmap + PCI_BAR0_SPROM_OFFSET), 0, b, sizeof (b), TRUE))
|
||||
return (-1);
|
||||
|
||||
/* top word of sprom contains version and crc8 */
|
||||
sromrev = b[63] & 0xff;
|
||||
if ((sromrev != 1) && (sromrev != 2)) {
|
||||
return (-2);
|
||||
}
|
||||
|
||||
ASSERT(vars);
|
||||
ASSERT(count);
|
||||
|
||||
base = vp = MALLOC(VARS_MAX);
|
||||
ASSERT(vp);
|
||||
|
||||
vp += sprintf(vp, "sromrev=%d", sromrev);
|
||||
vp++;
|
||||
|
||||
if (sromrev >= 2) {
|
||||
/* New section takes over the 4th hardware function space */
|
||||
|
||||
/* Word 29 is max power 11a high/low */
|
||||
w = b[29];
|
||||
vp += sprintf(vp, "pa1himaxpwr=%d", w & 0xff);
|
||||
vp++;
|
||||
vp += sprintf(vp, "pa1lomaxpwr=%d", (w >> 8) & 0xff);
|
||||
vp++;
|
||||
|
||||
/* Words 30-32 set the 11alow pa settings,
|
||||
* 33-35 are the 11ahigh ones.
|
||||
*/
|
||||
for (i = 0; i < 3; i++) {
|
||||
vp += sprintf(vp, "pa1lob%d=%d", i, b[30 + i]);
|
||||
vp++;
|
||||
vp += sprintf(vp, "pa1hib%d=%d", i, b[33 + i]);
|
||||
vp++;
|
||||
}
|
||||
w = b[59];
|
||||
if (w == 0)
|
||||
vp += sprintf(vp, "ccode=");
|
||||
else
|
||||
vp += sprintf(vp, "ccode=%c%c", (w >> 8), (w & 0xff));
|
||||
vp++;
|
||||
|
||||
}
|
||||
|
||||
/* parameter section of sprom starts at byte offset 72 */
|
||||
woff = 72/2;
|
||||
|
||||
/* first 6 bytes are il0macaddr */
|
||||
ea.octet[0] = (b[woff] >> 8) & 0xff;
|
||||
ea.octet[1] = b[woff] & 0xff;
|
||||
ea.octet[2] = (b[woff+1] >> 8) & 0xff;
|
||||
ea.octet[3] = b[woff+1] & 0xff;
|
||||
ea.octet[4] = (b[woff+2] >> 8) & 0xff;
|
||||
ea.octet[5] = b[woff+2] & 0xff;
|
||||
woff += ETHER_ADDR_LEN/2 ;
|
||||
bcm_ether_ntoa((uchar*)&ea, eabuf);
|
||||
vp += sprintf(vp, "il0macaddr=%s", eabuf);
|
||||
vp++;
|
||||
|
||||
/* next 6 bytes are et0macaddr */
|
||||
ea.octet[0] = (b[woff] >> 8) & 0xff;
|
||||
ea.octet[1] = b[woff] & 0xff;
|
||||
ea.octet[2] = (b[woff+1] >> 8) & 0xff;
|
||||
ea.octet[3] = b[woff+1] & 0xff;
|
||||
ea.octet[4] = (b[woff+2] >> 8) & 0xff;
|
||||
ea.octet[5] = b[woff+2] & 0xff;
|
||||
woff += ETHER_ADDR_LEN/2 ;
|
||||
bcm_ether_ntoa((uchar*)&ea, eabuf);
|
||||
vp += sprintf(vp, "et0macaddr=%s", eabuf);
|
||||
vp++;
|
||||
|
||||
/* next 6 bytes are et1macaddr */
|
||||
ea.octet[0] = (b[woff] >> 8) & 0xff;
|
||||
ea.octet[1] = b[woff] & 0xff;
|
||||
ea.octet[2] = (b[woff+1] >> 8) & 0xff;
|
||||
ea.octet[3] = b[woff+1] & 0xff;
|
||||
ea.octet[4] = (b[woff+2] >> 8) & 0xff;
|
||||
ea.octet[5] = b[woff+2] & 0xff;
|
||||
woff += ETHER_ADDR_LEN/2 ;
|
||||
bcm_ether_ntoa((uchar*)&ea, eabuf);
|
||||
vp += sprintf(vp, "et1macaddr=%s", eabuf);
|
||||
vp++;
|
||||
|
||||
/*
|
||||
* Enet phy settings one or two singles or a dual
|
||||
* Bits 4-0 : MII address for enet0 (0x1f for not there)
|
||||
* Bits 9-5 : MII address for enet1 (0x1f for not there)
|
||||
* Bit 14 : Mdio for enet0
|
||||
* Bit 15 : Mdio for enet1
|
||||
*/
|
||||
w = b[woff];
|
||||
vp += sprintf(vp, "et0phyaddr=%d", (w & 0x1f));
|
||||
vp++;
|
||||
vp += sprintf(vp, "et1phyaddr=%d", ((w >> 5) & 0x1f));
|
||||
vp++;
|
||||
vp += sprintf(vp, "et0mdcport=%d", ((w >> 14) & 0x1));
|
||||
vp++;
|
||||
vp += sprintf(vp, "et1mdcport=%d", ((w >> 15) & 0x1));
|
||||
vp++;
|
||||
|
||||
/* Word 46 has board rev, antennas 0/1 & Country code/control */
|
||||
w = b[46];
|
||||
vp += sprintf(vp, "boardrev=%d", w & 0xff);
|
||||
vp++;
|
||||
|
||||
if (sromrev > 1)
|
||||
vp += sprintf(vp, "cctl=%d", (w >> 8) & 0xf);
|
||||
else
|
||||
vp += sprintf(vp, "cc=%d", (w >> 8) & 0xf);
|
||||
vp++;
|
||||
|
||||
vp += sprintf(vp, "aa0=%d", (w >> 12) & 0x3);
|
||||
vp++;
|
||||
|
||||
vp += sprintf(vp, "aa1=%d", (w >> 14) & 0x3);
|
||||
vp++;
|
||||
|
||||
/* Words 47-49 set the (wl) pa settings */
|
||||
woff = 47;
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
vp += sprintf(vp, "pa0b%d=%d", i, b[woff+i]);
|
||||
vp++;
|
||||
vp += sprintf(vp, "pa1b%d=%d", i, b[woff+i+6]);
|
||||
vp++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Words 50-51 set the customer-configured wl led behavior.
|
||||
* 8 bits/gpio pin. High bit: activehi=0, activelo=1;
|
||||
* LED behavior values defined in wlioctl.h .
|
||||
*/
|
||||
w = b[50];
|
||||
if ((w != 0) && (w != 0xffff)) {
|
||||
/* gpio0 */
|
||||
vp += sprintf(vp, "wl0gpio0=%d", (w & 0xff));
|
||||
vp++;
|
||||
|
||||
/* gpio1 */
|
||||
vp += sprintf(vp, "wl0gpio1=%d", (w >> 8) & 0xff);
|
||||
vp++;
|
||||
}
|
||||
w = b[51];
|
||||
if ((w != 0) && (w != 0xffff)) {
|
||||
/* gpio2 */
|
||||
vp += sprintf(vp, "wl0gpio2=%d", w & 0xff);
|
||||
vp++;
|
||||
|
||||
/* gpio3 */
|
||||
vp += sprintf(vp, "wl0gpio3=%d", (w >> 8) & 0xff);
|
||||
vp++;
|
||||
}
|
||||
|
||||
/* Word 52 is max power 0/1 */
|
||||
w = b[52];
|
||||
vp += sprintf(vp, "pa0maxpwr=%d", w & 0xff);
|
||||
vp++;
|
||||
vp += sprintf(vp, "pa1maxpwr=%d", (w >> 8) & 0xff);
|
||||
vp++;
|
||||
|
||||
/* Word 56 is idle tssi target 0/1 */
|
||||
w = b[56];
|
||||
vp += sprintf(vp, "pa0itssit=%d", w & 0xff);
|
||||
vp++;
|
||||
vp += sprintf(vp, "pa1itssit=%d", (w >> 8) & 0xff);
|
||||
vp++;
|
||||
|
||||
/* Word 57 is boardflags, if not programmed make it zero */
|
||||
bfl = (uint32)b[57];
|
||||
if (bfl == 0xffff) bfl = 0;
|
||||
if (sromrev > 1) {
|
||||
/* Word 28 is boardflags2 */
|
||||
bfl |= (uint32)b[28] << 16;
|
||||
}
|
||||
vp += sprintf(vp, "boardflags=%d", bfl);
|
||||
vp++;
|
||||
|
||||
/* Word 58 is antenna gain 0/1 */
|
||||
w = b[58];
|
||||
vp += sprintf(vp, "ag0=%d", w & 0xff);
|
||||
vp++;
|
||||
|
||||
vp += sprintf(vp, "ag1=%d", (w >> 8) & 0xff);
|
||||
vp++;
|
||||
|
||||
if (sromrev == 1) {
|
||||
/* set the oem string */
|
||||
vp += sprintf(vp, "oem=%02x%02x%02x%02x%02x%02x%02x%02x",
|
||||
((b[59] >> 8) & 0xff), (b[59] & 0xff),
|
||||
((b[60] >> 8) & 0xff), (b[60] & 0xff),
|
||||
((b[61] >> 8) & 0xff), (b[61] & 0xff),
|
||||
((b[62] >> 8) & 0xff), (b[62] & 0xff));
|
||||
vp++;
|
||||
} else {
|
||||
if (sromrev >= 1){
|
||||
/* Word 60 OFDM tx power offset from CCK level */
|
||||
/* OFDM Power Offset - opo */
|
||||
w = b[60] & 0xff;
|
||||
if (w == 0xff)
|
||||
w = 16;
|
||||
vp += sprintf(vp, "opo=%d", w);
|
||||
vp++;
|
||||
}
|
||||
}
|
||||
|
||||
/* final nullbyte terminator */
|
||||
*vp++ = '\0';
|
||||
|
||||
c = vp - base;
|
||||
ASSERT(c <= VARS_MAX);
|
||||
|
||||
if (c == VARS_MAX) {
|
||||
*vars = base;
|
||||
} else {
|
||||
vp = MALLOC(c);
|
||||
ASSERT(vp);
|
||||
bcopy(base, vp, c);
|
||||
MFREE(base, VARS_MAX);
|
||||
*vars = vp;
|
||||
}
|
||||
*count = c;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the cis and call parsecis to initialize the vars.
|
||||
* Return 0 on success, nonzero on error.
|
||||
*/
|
||||
static int
|
||||
initvars_cis_pcmcia(void *sbh, void *curmap, void *osh, char **vars, int *count)
|
||||
{
|
||||
uint8 *cis = NULL;
|
||||
int rc;
|
||||
uint data_sz;
|
||||
|
||||
data_sz = (sb_pcmciarev(sbh) == 1) ? (SPROM_SIZE * 2) : CIS_SIZE;
|
||||
|
||||
if ((cis = MALLOC(data_sz)) == NULL)
|
||||
return (-1);
|
||||
|
||||
if (sb_pcmciarev(sbh) == 1) {
|
||||
if (srom_read(PCMCIA_BUS, (void *)NULL, osh, 0, data_sz, (uint16 *)cis)) {
|
||||
MFREE(cis, data_sz);
|
||||
return (-1);
|
||||
}
|
||||
/* fix up endianess for 16-bit data vs 8-bit parsing */
|
||||
ltoh16_buf((uint16 *)cis, data_sz);
|
||||
} else
|
||||
OSL_PCMCIA_READ_ATTR(osh, 0, cis, data_sz);
|
||||
|
||||
rc = srom_parsecis(cis, vars, count);
|
||||
|
||||
MFREE(cis, data_sz);
|
||||
|
||||
return (rc);
|
||||
}
|
||||
|
||||
803
package/linux/kernel-source/drivers/net/hnd/bcmutils.c
Normal file
803
package/linux/kernel-source/drivers/net/hnd/bcmutils.c
Normal file
@@ -0,0 +1,803 @@
|
||||
/*
|
||||
* Misc useful OS-independent routines.
|
||||
*
|
||||
* Copyright 2004, Broadcom Corporation
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
|
||||
* KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
|
||||
* SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#include <typedefs.h>
|
||||
#include <osl.h>
|
||||
#include <bcmutils.h>
|
||||
#include <bcmendian.h>
|
||||
#include <bcmnvram.h>
|
||||
|
||||
unsigned char bcm_ctype[] = {
|
||||
_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 0-7 */
|
||||
_BCM_C,_BCM_C|_BCM_S,_BCM_C|_BCM_S,_BCM_C|_BCM_S,_BCM_C|_BCM_S,_BCM_C|_BCM_S,_BCM_C,_BCM_C, /* 8-15 */
|
||||
_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 16-23 */
|
||||
_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 24-31 */
|
||||
_BCM_S|_BCM_SP,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 32-39 */
|
||||
_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 40-47 */
|
||||
_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D, /* 48-55 */
|
||||
_BCM_D,_BCM_D,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 56-63 */
|
||||
_BCM_P,_BCM_U|_BCM_X,_BCM_U|_BCM_X,_BCM_U|_BCM_X,_BCM_U|_BCM_X,_BCM_U|_BCM_X,_BCM_U|_BCM_X,_BCM_U, /* 64-71 */
|
||||
_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U, /* 72-79 */
|
||||
_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U, /* 80-87 */
|
||||
_BCM_U,_BCM_U,_BCM_U,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 88-95 */
|
||||
_BCM_P,_BCM_L|_BCM_X,_BCM_L|_BCM_X,_BCM_L|_BCM_X,_BCM_L|_BCM_X,_BCM_L|_BCM_X,_BCM_L|_BCM_X,_BCM_L, /* 96-103 */
|
||||
_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L, /* 104-111 */
|
||||
_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L, /* 112-119 */
|
||||
_BCM_L,_BCM_L,_BCM_L,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_C, /* 120-127 */
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 128-143 */
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 144-159 */
|
||||
_BCM_S|_BCM_SP,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 160-175 */
|
||||
_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 176-191 */
|
||||
_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U, /* 192-207 */
|
||||
_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_P,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_L, /* 208-223 */
|
||||
_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L, /* 224-239 */
|
||||
_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_P,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L /* 240-255 */
|
||||
};
|
||||
|
||||
uchar
|
||||
bcm_toupper(uchar c)
|
||||
{
|
||||
if (bcm_islower(c))
|
||||
c -= 'a'-'A';
|
||||
return (c);
|
||||
}
|
||||
|
||||
ulong
|
||||
bcm_strtoul(char *cp, char **endp, uint base)
|
||||
{
|
||||
ulong result, value;
|
||||
bool minus;
|
||||
|
||||
minus = FALSE;
|
||||
|
||||
while (bcm_isspace(*cp))
|
||||
cp++;
|
||||
|
||||
if (cp[0] == '+')
|
||||
cp++;
|
||||
else if (cp[0] == '-') {
|
||||
minus = TRUE;
|
||||
cp++;
|
||||
}
|
||||
|
||||
if (base == 0) {
|
||||
if (cp[0] == '0') {
|
||||
if ((cp[1] == 'x') || (cp[1] == 'X')) {
|
||||
base = 16;
|
||||
cp = &cp[2];
|
||||
} else {
|
||||
base = 8;
|
||||
cp = &cp[1];
|
||||
}
|
||||
} else
|
||||
base = 10;
|
||||
} else if (base == 16 && (cp[0] == '0') && ((cp[1] == 'x') || (cp[1] == 'X'))) {
|
||||
cp = &cp[2];
|
||||
}
|
||||
|
||||
result = 0;
|
||||
|
||||
while (bcm_isxdigit(*cp) &&
|
||||
(value = bcm_isdigit(*cp) ? *cp-'0' : bcm_toupper(*cp)-'A'+10) < base) {
|
||||
result = result*base + value;
|
||||
cp++;
|
||||
}
|
||||
|
||||
if (minus)
|
||||
result = (ulong)(result * -1);
|
||||
|
||||
if (endp)
|
||||
*endp = (char *)cp;
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
uint
|
||||
bcm_atoi(char *s)
|
||||
{
|
||||
uint n;
|
||||
|
||||
n = 0;
|
||||
|
||||
while (bcm_isdigit(*s))
|
||||
n = (n * 10) + *s++ - '0';
|
||||
return (n);
|
||||
}
|
||||
|
||||
void
|
||||
deadbeef(char *p, uint len)
|
||||
{
|
||||
static uchar meat[] = { 0xde, 0xad, 0xbe, 0xef };
|
||||
|
||||
while (len-- > 0) {
|
||||
*p = meat[((uint)p) & 3];
|
||||
p++;
|
||||
}
|
||||
}
|
||||
|
||||
/* pretty hex print a contiguous buffer */
|
||||
void
|
||||
prhex(char *msg, uchar *buf, uint nbytes)
|
||||
{
|
||||
char line[256];
|
||||
char* p;
|
||||
uint i;
|
||||
|
||||
if (msg && (msg[0] != '\0'))
|
||||
printf("%s: ", msg);
|
||||
|
||||
p = line;
|
||||
for (i = 0; i < nbytes; i++) {
|
||||
if (i % 16 == 0) {
|
||||
p += sprintf(p, "%04d: ", i); /* line prefix */
|
||||
}
|
||||
p += sprintf(p, "%02x ", buf[i]);
|
||||
if (i % 16 == 15) {
|
||||
printf("%s\n", line); /* flush line */
|
||||
p = line;
|
||||
}
|
||||
}
|
||||
|
||||
/* flush last partial line */
|
||||
if (p != line)
|
||||
printf("%s\n", line);
|
||||
}
|
||||
|
||||
/* pretty hex print a pkt buffer chain */
|
||||
void
|
||||
prpkt(char *msg, void *drv, void *p0)
|
||||
{
|
||||
void *p;
|
||||
|
||||
if (msg && (msg[0] != '\0'))
|
||||
printf("%s: ", msg);
|
||||
|
||||
for (p = p0; p; p = PKTNEXT(drv, p))
|
||||
prhex(NULL, PKTDATA(drv, p), PKTLEN(drv, p));
|
||||
}
|
||||
|
||||
/* copy a pkt buffer chain into a buffer */
|
||||
uint
|
||||
pktcopy(void *drv, void *p, uint offset, int len, uchar *buf)
|
||||
{
|
||||
uint n, ret = 0;
|
||||
|
||||
if (len < 0)
|
||||
len = 4096; /* "infinite" */
|
||||
|
||||
/* skip 'offset' bytes */
|
||||
for (; p && offset; p = PKTNEXT(drv, p)) {
|
||||
if (offset < (uint)PKTLEN(drv, p))
|
||||
break;
|
||||
offset -= PKTLEN(drv, p);
|
||||
}
|
||||
|
||||
if (!p)
|
||||
return 0;
|
||||
|
||||
/* copy the data */
|
||||
for (; p && len; p = PKTNEXT(drv, p)) {
|
||||
n = MIN((uint)PKTLEN(drv, p) - offset, (uint)len);
|
||||
bcopy(PKTDATA(drv, p) + offset, buf, n);
|
||||
buf += n;
|
||||
len -= n;
|
||||
ret += n;
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* return total length of buffer chain */
|
||||
uint
|
||||
pkttotlen(void *drv, void *p)
|
||||
{
|
||||
uint total;
|
||||
|
||||
total = 0;
|
||||
for (; p; p = PKTNEXT(drv, p))
|
||||
total += PKTLEN(drv, p);
|
||||
return (total);
|
||||
}
|
||||
|
||||
|
||||
uchar*
|
||||
bcm_ether_ntoa(char *ea, char *buf)
|
||||
{
|
||||
sprintf(buf,"%02x:%02x:%02x:%02x:%02x:%02x",
|
||||
(uchar)ea[0]&0xff, (uchar)ea[1]&0xff, (uchar)ea[2]&0xff,
|
||||
(uchar)ea[3]&0xff, (uchar)ea[4]&0xff, (uchar)ea[5]&0xff);
|
||||
return (buf);
|
||||
}
|
||||
|
||||
/* parse a xx:xx:xx:xx:xx:xx format ethernet address */
|
||||
int
|
||||
bcm_ether_atoe(char *p, char *ea)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
for (;;) {
|
||||
ea[i++] = (char) bcm_strtoul(p, &p, 16);
|
||||
if (!*p++ || i == 6)
|
||||
break;
|
||||
}
|
||||
|
||||
return (i == 6);
|
||||
}
|
||||
|
||||
/*
|
||||
* Advance from the current 1-byte tag/1-byte length/variable-length value
|
||||
* triple, to the next, returning a pointer to the next.
|
||||
*/
|
||||
bcm_tlv_t *
|
||||
bcm_next_tlv(bcm_tlv_t *elt, int *buflen)
|
||||
{
|
||||
int len;
|
||||
|
||||
/* validate current elt */
|
||||
if (*buflen < 2) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
len = elt->len;
|
||||
|
||||
/* validate remaining buflen */
|
||||
if (*buflen >= (2 + len + 2)) {
|
||||
elt = (bcm_tlv_t*)(elt->data + len);
|
||||
*buflen -= (2 + len);
|
||||
} else {
|
||||
elt = NULL;
|
||||
}
|
||||
|
||||
return elt;
|
||||
}
|
||||
|
||||
/*
|
||||
* Traverse a string of 1-byte tag/1-byte length/variable-length value
|
||||
* triples, returning a pointer to the substring whose first element
|
||||
* matches tag. Stop parsing when we see an element whose ID is greater
|
||||
* than the target key.
|
||||
*/
|
||||
bcm_tlv_t *
|
||||
bcm_parse_ordered_tlvs(void *buf, int buflen, uint key)
|
||||
{
|
||||
bcm_tlv_t *elt;
|
||||
int totlen;
|
||||
|
||||
elt = (bcm_tlv_t*)buf;
|
||||
totlen = buflen;
|
||||
|
||||
/* find tagged parameter */
|
||||
while (totlen >= 2) {
|
||||
uint id = elt->id;
|
||||
int len = elt->len;
|
||||
|
||||
/* Punt if we start seeing IDs > than target key */
|
||||
if (id > key)
|
||||
return(NULL);
|
||||
|
||||
/* validate remaining totlen */
|
||||
if ((id == key) && (totlen >= (len + 2)))
|
||||
return (elt);
|
||||
|
||||
elt = (bcm_tlv_t*)((uint8*)elt + (len + 2));
|
||||
totlen -= (len + 2);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Traverse a string of 1-byte tag/1-byte length/variable-length value
|
||||
* triples, returning a pointer to the substring whose first element
|
||||
* matches tag
|
||||
*/
|
||||
bcm_tlv_t *
|
||||
bcm_parse_tlvs(void *buf, int buflen, uint key)
|
||||
{
|
||||
bcm_tlv_t *elt;
|
||||
int totlen;
|
||||
|
||||
elt = (bcm_tlv_t*)buf;
|
||||
totlen = buflen;
|
||||
|
||||
/* find tagged parameter */
|
||||
while (totlen >= 2) {
|
||||
int len = elt->len;
|
||||
|
||||
/* validate remaining totlen */
|
||||
if ((elt->id == key) && (totlen >= (len + 2)))
|
||||
return (elt);
|
||||
|
||||
elt = (bcm_tlv_t*)((uint8*)elt + (len + 2));
|
||||
totlen -= (len + 2);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
pktq_init(struct pktq *q, uint maxlen, bool priority)
|
||||
{
|
||||
q->head = q->tail = NULL;
|
||||
q->priority = priority;
|
||||
q->maxlen = maxlen;
|
||||
q->len = 0;
|
||||
}
|
||||
|
||||
bool
|
||||
pktenq(struct pktq *q, void *p, bool lifo)
|
||||
{
|
||||
void *next, *prev;
|
||||
|
||||
/* Queue is full */
|
||||
if (q->len >= q->maxlen)
|
||||
return FALSE;
|
||||
|
||||
/* Queueing chains not allowed */
|
||||
ASSERT(PKTLINK(p) == NULL);
|
||||
|
||||
/* Queue is empty */
|
||||
if (q->tail == NULL) {
|
||||
ASSERT(q->head == NULL);
|
||||
q->head = q->tail = p;
|
||||
}
|
||||
|
||||
/* Insert at head or tail */
|
||||
else if (q->priority == FALSE) {
|
||||
/* Insert at head (LIFO) */
|
||||
if (lifo) {
|
||||
PKTSETLINK(p, q->head);
|
||||
q->head = p;
|
||||
}
|
||||
/* Insert at tail (FIFO) */
|
||||
else {
|
||||
ASSERT(PKTLINK(q->tail) == NULL);
|
||||
PKTSETLINK(q->tail, p);
|
||||
PKTSETLINK(p, NULL);
|
||||
q->tail = p;
|
||||
}
|
||||
}
|
||||
|
||||
/* Insert by priority */
|
||||
else {
|
||||
ASSERT(q->head);
|
||||
ASSERT(q->tail);
|
||||
/* Shortcut to insertion at tail */
|
||||
if (PKTPRIO(p) < PKTPRIO(q->tail) ||
|
||||
(!lifo && PKTPRIO(p) <= PKTPRIO(q->tail))) {
|
||||
prev = q->tail;
|
||||
next = NULL;
|
||||
}
|
||||
/* Insert at head or in the middle */
|
||||
else {
|
||||
prev = NULL;
|
||||
next = q->head;
|
||||
}
|
||||
/* Walk the queue */
|
||||
for (; next; prev = next, next = PKTLINK(next)) {
|
||||
/* Priority queue invariant */
|
||||
ASSERT(!prev || PKTPRIO(prev) >= PKTPRIO(next));
|
||||
/* Insert at head of string of packets of same priority (LIFO) */
|
||||
if (lifo) {
|
||||
if (PKTPRIO(p) >= PKTPRIO(next))
|
||||
break;
|
||||
}
|
||||
/* Insert at tail of string of packets of same priority (FIFO) */
|
||||
else {
|
||||
if (PKTPRIO(p) > PKTPRIO(next))
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Insert at tail */
|
||||
if (next == NULL) {
|
||||
ASSERT(PKTLINK(q->tail) == NULL);
|
||||
PKTSETLINK(q->tail, p);
|
||||
PKTSETLINK(p, NULL);
|
||||
q->tail = p;
|
||||
}
|
||||
/* Insert in the middle */
|
||||
else if (prev) {
|
||||
PKTSETLINK(prev, p);
|
||||
PKTSETLINK(p, next);
|
||||
}
|
||||
/* Insert at head */
|
||||
else {
|
||||
PKTSETLINK(p, q->head);
|
||||
q->head = p;
|
||||
}
|
||||
}
|
||||
|
||||
/* List invariants after insertion */
|
||||
ASSERT(q->head);
|
||||
ASSERT(PKTLINK(q->tail) == NULL);
|
||||
|
||||
q->len++;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void*
|
||||
pktdeq(struct pktq *q)
|
||||
{
|
||||
void *p;
|
||||
|
||||
if ((p = q->head)) {
|
||||
ASSERT(q->tail);
|
||||
q->head = PKTLINK(p);
|
||||
PKTSETLINK(p, NULL);
|
||||
q->len--;
|
||||
if (q->head == NULL)
|
||||
q->tail = NULL;
|
||||
}
|
||||
else {
|
||||
ASSERT(q->tail == NULL);
|
||||
}
|
||||
|
||||
return (p);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* crc8
|
||||
*
|
||||
* Computes a crc8 over the input data using the polynomial:
|
||||
*
|
||||
* x^8 + x^7 +x^6 + x^4 + x^2 + 1
|
||||
*
|
||||
* The caller provides the initial value (either CRC8_INIT_VALUE
|
||||
* or the previous returned value) to allow for processing of
|
||||
* discontiguous blocks of data. When generating the CRC the
|
||||
* caller is responsible for complementing the final return value
|
||||
* and inserting it into the byte stream. When checking, a final
|
||||
* return value of CRC8_GOOD_VALUE indicates a valid CRC.
|
||||
*
|
||||
* Reference: Dallas Semiconductor Application Note 27
|
||||
* Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
|
||||
* ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
|
||||
* ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
static uint8 crc8_table[256] = {
|
||||
0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
|
||||
0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
|
||||
0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
|
||||
0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
|
||||
0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
|
||||
0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
|
||||
0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
|
||||
0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
|
||||
0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
|
||||
0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
|
||||
0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
|
||||
0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
|
||||
0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
|
||||
0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
|
||||
0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
|
||||
0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
|
||||
0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
|
||||
0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
|
||||
0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
|
||||
0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
|
||||
0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
|
||||
0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
|
||||
0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
|
||||
0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
|
||||
0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
|
||||
0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
|
||||
0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
|
||||
0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
|
||||
0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
|
||||
0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
|
||||
0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
|
||||
0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F
|
||||
};
|
||||
|
||||
/*
|
||||
* Search the name=value vars for a specific one and return its value.
|
||||
* Returns NULL if not found.
|
||||
*/
|
||||
char*
|
||||
getvar(char *vars, char *name)
|
||||
{
|
||||
char *s;
|
||||
int len;
|
||||
|
||||
len = strlen(name);
|
||||
|
||||
/* first look in vars[] */
|
||||
for (s = vars; s && *s; ) {
|
||||
if ((bcmp(s, name, len) == 0) && (s[len] == '='))
|
||||
return (&s[len+1]);
|
||||
|
||||
while (*s++)
|
||||
;
|
||||
}
|
||||
|
||||
/* then query nvram */
|
||||
return (nvram_get(name));
|
||||
}
|
||||
|
||||
/*
|
||||
* Search the vars for a specific one and return its value as
|
||||
* an integer. Returns 0 if not found.
|
||||
*/
|
||||
int
|
||||
getintvar(char *vars, char *name)
|
||||
{
|
||||
char *val;
|
||||
|
||||
if ((val = getvar(vars, name)) == NULL)
|
||||
return (0);
|
||||
|
||||
return (bcm_strtoul(val, NULL, 0));
|
||||
}
|
||||
|
||||
/* return pointer to location of substring 'needle' in 'haystack' */
|
||||
char*
|
||||
bcmstrstr(char *haystack, char *needle)
|
||||
{
|
||||
int len, nlen;
|
||||
int i;
|
||||
|
||||
if ((haystack == NULL) || (needle == NULL))
|
||||
return (haystack);
|
||||
|
||||
nlen = strlen(needle);
|
||||
len = strlen(haystack) - nlen + 1;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
if (bcmp(needle, &haystack[i], nlen) == 0)
|
||||
return (&haystack[i]);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
void
|
||||
bcm_mdelay(uint ms)
|
||||
{
|
||||
uint i;
|
||||
|
||||
for (i = 0; i < ms; i++) {
|
||||
OSL_DELAY(1000);
|
||||
}
|
||||
}
|
||||
|
||||
#define CRC_INNER_LOOP(n, c, x) \
|
||||
(c) = ((c) >> 8) ^ crc##n##_table[((c) ^ (x)) & 0xff]
|
||||
|
||||
uint8
|
||||
crc8(
|
||||
uint8 *pdata, /* pointer to array of data to process */
|
||||
uint nbytes, /* number of input data bytes to process */
|
||||
uint8 crc /* either CRC8_INIT_VALUE or previous return value */
|
||||
)
|
||||
{
|
||||
/* hard code the crc loop instead of using CRC_INNER_LOOP macro
|
||||
* to avoid the undefined and unnecessary (uint8 >> 8) operation. */
|
||||
while (nbytes-- > 0)
|
||||
crc = crc8_table[(crc ^ *pdata++) & 0xff];
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* crc16
|
||||
*
|
||||
* Computes a crc16 over the input data using the polynomial:
|
||||
*
|
||||
* x^16 + x^12 +x^5 + 1
|
||||
*
|
||||
* The caller provides the initial value (either CRC16_INIT_VALUE
|
||||
* or the previous returned value) to allow for processing of
|
||||
* discontiguous blocks of data. When generating the CRC the
|
||||
* caller is responsible for complementing the final return value
|
||||
* and inserting it into the byte stream. When checking, a final
|
||||
* return value of CRC16_GOOD_VALUE indicates a valid CRC.
|
||||
*
|
||||
* Reference: Dallas Semiconductor Application Note 27
|
||||
* Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
|
||||
* ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
|
||||
* ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
static uint16 crc16_table[256] = {
|
||||
0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF,
|
||||
0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7,
|
||||
0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E,
|
||||
0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876,
|
||||
0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD,
|
||||
0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5,
|
||||
0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C,
|
||||
0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974,
|
||||
0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB,
|
||||
0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3,
|
||||
0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A,
|
||||
0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72,
|
||||
0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9,
|
||||
0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1,
|
||||
0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738,
|
||||
0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70,
|
||||
0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7,
|
||||
0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF,
|
||||
0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036,
|
||||
0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E,
|
||||
0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5,
|
||||
0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD,
|
||||
0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134,
|
||||
0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C,
|
||||
0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3,
|
||||
0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB,
|
||||
0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232,
|
||||
0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A,
|
||||
0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1,
|
||||
0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9,
|
||||
0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330,
|
||||
0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78
|
||||
};
|
||||
|
||||
uint16
|
||||
crc16(
|
||||
uint8 *pdata, /* pointer to array of data to process */
|
||||
uint nbytes, /* number of input data bytes to process */
|
||||
uint16 crc /* either CRC16_INIT_VALUE or previous return value */
|
||||
)
|
||||
{
|
||||
while (nbytes-- > 0)
|
||||
CRC_INNER_LOOP(16, crc, *pdata++);
|
||||
return crc;
|
||||
}
|
||||
|
||||
static uint32 crc32_table[256] = {
|
||||
0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
|
||||
0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
|
||||
0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
|
||||
0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
|
||||
0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
|
||||
0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
|
||||
0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
|
||||
0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
|
||||
0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
|
||||
0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
|
||||
0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
|
||||
0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
|
||||
0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
|
||||
0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
|
||||
0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
|
||||
0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
|
||||
0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
|
||||
0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
|
||||
0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
|
||||
0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
|
||||
0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
|
||||
0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
|
||||
0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
|
||||
0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
|
||||
0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
|
||||
0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
|
||||
0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
|
||||
0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
|
||||
0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
|
||||
0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
|
||||
0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
|
||||
0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
|
||||
0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
|
||||
0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
|
||||
0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
|
||||
0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
|
||||
0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
|
||||
0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
|
||||
0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
|
||||
0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
|
||||
0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
|
||||
0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
|
||||
0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
|
||||
0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
|
||||
0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
|
||||
0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
|
||||
0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
|
||||
0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
|
||||
0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
|
||||
0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
|
||||
0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
|
||||
0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
|
||||
0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
|
||||
0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
|
||||
0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
|
||||
0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
|
||||
0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
|
||||
0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
|
||||
0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
|
||||
0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
|
||||
0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
|
||||
0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
|
||||
0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
|
||||
0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
|
||||
};
|
||||
|
||||
uint32
|
||||
crc32(
|
||||
uint8 *pdata, /* pointer to array of data to process */
|
||||
uint nbytes, /* number of input data bytes to process */
|
||||
uint32 crc /* either CRC32_INIT_VALUE or previous return value */
|
||||
)
|
||||
{
|
||||
uint8 *pend;
|
||||
#ifdef __mips__
|
||||
uint8 tmp[4];
|
||||
ulong *tptr = (ulong *)tmp;
|
||||
|
||||
/* in case the beginning of the buffer isn't aligned */
|
||||
pend = (uint8 *)((uint)(pdata + 3) & 0xfffffffc);
|
||||
nbytes -= (pend - pdata);
|
||||
while (pdata < pend)
|
||||
CRC_INNER_LOOP(32, crc, *pdata++);
|
||||
|
||||
/* handle bulk of data as 32-bit words */
|
||||
pend = pdata + (nbytes & 0xfffffffc);
|
||||
while (pdata < pend) {
|
||||
*tptr = *((ulong *)pdata)++;
|
||||
CRC_INNER_LOOP(32, crc, tmp[0]);
|
||||
CRC_INNER_LOOP(32, crc, tmp[1]);
|
||||
CRC_INNER_LOOP(32, crc, tmp[2]);
|
||||
CRC_INNER_LOOP(32, crc, tmp[3]);
|
||||
}
|
||||
|
||||
/* 1-3 bytes at end of buffer */
|
||||
pend = pdata + (nbytes & 0x03);
|
||||
while (pdata < pend)
|
||||
CRC_INNER_LOOP(32, crc, *pdata++);
|
||||
#else
|
||||
pend = pdata + nbytes;
|
||||
while (pdata < pend)
|
||||
CRC_INNER_LOOP(32, crc, *pdata++);
|
||||
#endif
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
#ifdef notdef
|
||||
#define CLEN 1499
|
||||
#define CBUFSIZ (CLEN+4)
|
||||
#define CNBUFS 5
|
||||
|
||||
void testcrc32(void)
|
||||
{
|
||||
uint j,k,l;
|
||||
uint8 *buf;
|
||||
uint len[CNBUFS];
|
||||
uint32 crcr;
|
||||
uint32 crc32tv[CNBUFS] =
|
||||
{0xd2cb1faa, 0xd385c8fa, 0xf5b4f3f3, 0x55789e20, 0x00343110};
|
||||
|
||||
ASSERT((buf = MALLOC(CBUFSIZ*CNBUFS)) != NULL);
|
||||
|
||||
/* step through all possible alignments */
|
||||
for (l=0;l<=4;l++) {
|
||||
for (j=0; j<CNBUFS; j++) {
|
||||
len[j] = CLEN;
|
||||
for (k=0; k<len[j]; k++)
|
||||
*(buf + j*CBUFSIZ + (k+l)) = (j+k) & 0xff;
|
||||
}
|
||||
|
||||
for (j=0; j<CNBUFS; j++) {
|
||||
crcr = crc32(buf + j*CBUFSIZ + l, len[j], CRC32_INIT_VALUE);
|
||||
ASSERT(crcr == crc32tv[j]);
|
||||
}
|
||||
}
|
||||
|
||||
MFREE(buf, CBUFSIZ*CNBUFS);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
841
package/linux/kernel-source/drivers/net/hnd/hnddma.c
Normal file
841
package/linux/kernel-source/drivers/net/hnd/hnddma.c
Normal file
@@ -0,0 +1,841 @@
|
||||
/*
|
||||
* Generic Broadcom Home Networking Division (HND) DMA module.
|
||||
* This supports the following chips: BCM42xx, 44xx, 47xx .
|
||||
*
|
||||
* Copyright 2004, Broadcom Corporation
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
|
||||
* KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
|
||||
* SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#include <typedefs.h>
|
||||
#include <osl.h>
|
||||
#include <bcmendian.h>
|
||||
#include <bcmutils.h>
|
||||
|
||||
struct dma_info; /* forward declaration */
|
||||
#define di_t struct dma_info
|
||||
#include <hnddma.h>
|
||||
|
||||
/* debug/trace */
|
||||
#define DMA_ERROR(args)
|
||||
#define DMA_TRACE(args)
|
||||
|
||||
/* default dma message level(if input msg_level pointer is null in dma_attach()) */
|
||||
static uint dma_msg_level = 0;
|
||||
|
||||
#define MAXNAMEL 8
|
||||
#define MAXDD (DMAMAXRINGSZ / sizeof (dmadd_t))
|
||||
|
||||
/* dma engine software state */
|
||||
typedef struct dma_info {
|
||||
hnddma_t hnddma; /* exported structure */
|
||||
uint *msg_level; /* message level pointer */
|
||||
|
||||
char name[MAXNAMEL]; /* callers name for diag msgs */
|
||||
void *drv; /* driver handle */
|
||||
void *dev; /* device handle */
|
||||
dmaregs_t *regs; /* dma engine registers */
|
||||
|
||||
dmadd_t *txd; /* pointer to chip-specific tx descriptor ring */
|
||||
uint txin; /* index of next descriptor to reclaim */
|
||||
uint txout; /* index of next descriptor to post */
|
||||
uint txavail; /* # free tx descriptors */
|
||||
void *txp[MAXDD]; /* parallel array of pointers to packets */
|
||||
ulong txdpa; /* physical address of descriptor ring */
|
||||
uint txdalign; /* #bytes added to alloc'd mem to align txd */
|
||||
|
||||
dmadd_t *rxd; /* pointer to chip-specific rx descriptor ring */
|
||||
uint rxin; /* index of next descriptor to reclaim */
|
||||
uint rxout; /* index of next descriptor to post */
|
||||
void *rxp[MAXDD]; /* parallel array of pointers to packets */
|
||||
ulong rxdpa; /* physical address of descriptor ring */
|
||||
uint rxdalign; /* #bytes added to alloc'd mem to align rxd */
|
||||
|
||||
/* tunables */
|
||||
uint ntxd; /* # tx descriptors */
|
||||
uint nrxd; /* # rx descriptors */
|
||||
uint rxbufsize; /* rx buffer size in bytes */
|
||||
uint nrxpost; /* # rx buffers to keep posted */
|
||||
uint rxoffset; /* rxcontrol offset */
|
||||
uint ddoffset; /* add to get dma address of descriptor ring */
|
||||
uint dataoffset; /* add to get dma address of data buffer */
|
||||
} dma_info_t;
|
||||
|
||||
/* descriptor bumping macros */
|
||||
#define TXD(x) ((x) & (di->ntxd - 1))
|
||||
#define RXD(x) ((x) & (di->nrxd - 1))
|
||||
#define NEXTTXD(i) TXD(i + 1)
|
||||
#define PREVTXD(i) TXD(i - 1)
|
||||
#define NEXTRXD(i) RXD(i + 1)
|
||||
#define NTXDACTIVE(h, t) TXD(t - h)
|
||||
#define NRXDACTIVE(h, t) RXD(t - h)
|
||||
|
||||
/* macros to convert between byte offsets and indexes */
|
||||
#define B2I(bytes) ((bytes) / sizeof (dmadd_t))
|
||||
#define I2B(index) ((index) * sizeof (dmadd_t))
|
||||
|
||||
void*
|
||||
dma_attach(void *drv, void *dev, char *name, dmaregs_t *regs, uint ntxd, uint nrxd,
|
||||
uint rxbufsize, uint nrxpost, uint rxoffset, uint ddoffset, uint dataoffset, uint *msg_level)
|
||||
{
|
||||
dma_info_t *di;
|
||||
void *va;
|
||||
|
||||
ASSERT(ntxd <= MAXDD);
|
||||
ASSERT(nrxd <= MAXDD);
|
||||
|
||||
/* allocate private info structure */
|
||||
if ((di = MALLOC(sizeof (dma_info_t))) == NULL)
|
||||
return (NULL);
|
||||
bzero((char*)di, sizeof (dma_info_t));
|
||||
|
||||
/* set message level */
|
||||
di->msg_level = msg_level ? msg_level : &dma_msg_level;
|
||||
|
||||
DMA_TRACE(("%s: dma_attach: drv 0x%x dev 0x%x regs 0x%x ntxd %d nrxd %d rxbufsize %d nrxpost %d rxoffset %d ddoffset 0x%x dataoffset 0x%x\n", name, (uint)drv, (uint)dev, (uint)regs, ntxd, nrxd, rxbufsize, nrxpost, rxoffset, ddoffset, dataoffset));
|
||||
|
||||
/* make a private copy of our callers name */
|
||||
strncpy(di->name, name, MAXNAMEL);
|
||||
di->name[MAXNAMEL-1] = '\0';
|
||||
|
||||
di->drv = drv;
|
||||
di->dev = dev;
|
||||
di->regs = regs;
|
||||
|
||||
/* allocate transmit descriptor ring */
|
||||
if (ntxd) {
|
||||
if ((va = DMA_ALLOC_CONSISTENT(dev, (DMAMAXRINGSZ + DMARINGALIGN), &di->txdpa)) == NULL)
|
||||
goto fail;
|
||||
di->txd = (dmadd_t*) ROUNDUP(va, DMARINGALIGN);
|
||||
di->txdalign = ((uint)di->txd - (uint)va);
|
||||
di->txdpa = di->txdpa + di->txdalign;
|
||||
ASSERT(ISALIGNED(di->txd, DMARINGALIGN));
|
||||
}
|
||||
|
||||
/* allocate receive descriptor ring */
|
||||
if (nrxd) {
|
||||
if ((va = DMA_ALLOC_CONSISTENT(dev, (DMAMAXRINGSZ + DMARINGALIGN), &di->rxdpa)) == NULL)
|
||||
goto fail;
|
||||
di->rxd = (dmadd_t*) ROUNDUP(va, DMARINGALIGN);
|
||||
di->rxdalign = ((uint)di->rxd - (uint)va);
|
||||
di->rxdpa = di->rxdpa + di->rxdalign;
|
||||
ASSERT(ISALIGNED(di->rxd, DMARINGALIGN));
|
||||
}
|
||||
|
||||
/* save tunables */
|
||||
di->ntxd = ntxd;
|
||||
di->nrxd = nrxd;
|
||||
di->rxbufsize = rxbufsize;
|
||||
di->nrxpost = nrxpost;
|
||||
di->rxoffset = rxoffset;
|
||||
di->ddoffset = ddoffset;
|
||||
di->dataoffset = dataoffset;
|
||||
|
||||
return ((void*)di);
|
||||
|
||||
fail:
|
||||
dma_detach((void*)di);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* may be called with core in reset */
|
||||
void
|
||||
dma_detach(dma_info_t *di)
|
||||
{
|
||||
if (di == NULL)
|
||||
return;
|
||||
|
||||
DMA_TRACE(("%s: dma_detach\n", di->name));
|
||||
|
||||
/* shouldn't be here if descriptors are unreclaimed */
|
||||
ASSERT(di->txin == di->txout);
|
||||
ASSERT(di->rxin == di->rxout);
|
||||
|
||||
/* free dma descriptor rings */
|
||||
if (di->txd)
|
||||
DMA_FREE_CONSISTENT(di->dev, (void *)((uint)di->txd - di->txdalign), (DMAMAXRINGSZ + DMARINGALIGN), di->txdpa);
|
||||
if (di->rxd)
|
||||
DMA_FREE_CONSISTENT(di->dev, (void *)((uint)di->rxd - di->rxdalign), (DMAMAXRINGSZ + DMARINGALIGN), di->rxdpa);
|
||||
|
||||
/* free our private info structure */
|
||||
MFREE((void*)di, sizeof (dma_info_t));
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
dma_txreset(dma_info_t *di)
|
||||
{
|
||||
uint32 status;
|
||||
|
||||
DMA_TRACE(("%s: dma_txreset\n", di->name));
|
||||
|
||||
/* suspend tx DMA first */
|
||||
W_REG(&di->regs->xmtcontrol, XC_SE);
|
||||
SPINWAIT((status = (R_REG(&di->regs->xmtstatus) & XS_XS_MASK)) != XS_XS_DISABLED &&
|
||||
status != XS_XS_IDLE &&
|
||||
status != XS_XS_STOPPED,
|
||||
10000);
|
||||
|
||||
W_REG(&di->regs->xmtcontrol, 0);
|
||||
SPINWAIT((status = (R_REG(&di->regs->xmtstatus) & XS_XS_MASK)) != XS_XS_DISABLED,
|
||||
10000);
|
||||
|
||||
if (status != XS_XS_DISABLED) {
|
||||
DMA_ERROR(("%s: dma_txreset: dma cannot be stopped\n", di->name));
|
||||
}
|
||||
|
||||
/* wait for the last transaction to complete */
|
||||
OSL_DELAY(300);
|
||||
}
|
||||
|
||||
void
|
||||
dma_rxreset(dma_info_t *di)
|
||||
{
|
||||
uint32 status;
|
||||
|
||||
DMA_TRACE(("%s: dma_rxreset\n", di->name));
|
||||
|
||||
W_REG(&di->regs->rcvcontrol, 0);
|
||||
SPINWAIT((status = (R_REG(&di->regs->rcvstatus) & RS_RS_MASK)) != RS_RS_DISABLED,
|
||||
10000);
|
||||
|
||||
if (status != RS_RS_DISABLED) {
|
||||
DMA_ERROR(("%s: dma_rxreset: dma cannot be stopped\n", di->name));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
dma_txinit(dma_info_t *di)
|
||||
{
|
||||
DMA_TRACE(("%s: dma_txinit\n", di->name));
|
||||
|
||||
di->txin = di->txout = 0;
|
||||
di->txavail = di->ntxd - 1;
|
||||
|
||||
/* clear tx descriptor ring */
|
||||
BZERO_SM((void*)di->txd, (di->ntxd * sizeof (dmadd_t)));
|
||||
|
||||
W_REG(&di->regs->xmtcontrol, XC_XE);
|
||||
W_REG(&di->regs->xmtaddr, (di->txdpa + di->ddoffset));
|
||||
}
|
||||
|
||||
bool
|
||||
dma_txenabled(dma_info_t *di)
|
||||
{
|
||||
uint32 xc;
|
||||
|
||||
/* If the chip is dead, it is not enabled :-) */
|
||||
xc = R_REG(&di->regs->xmtcontrol);
|
||||
return ((xc != 0xffffffff) && (xc & XC_XE));
|
||||
}
|
||||
|
||||
void
|
||||
dma_txsuspend(dma_info_t *di)
|
||||
{
|
||||
DMA_TRACE(("%s: dma_txsuspend\n", di->name));
|
||||
OR_REG(&di->regs->xmtcontrol, XC_SE);
|
||||
}
|
||||
|
||||
void
|
||||
dma_txresume(dma_info_t *di)
|
||||
{
|
||||
DMA_TRACE(("%s: dma_txresume\n", di->name));
|
||||
AND_REG(&di->regs->xmtcontrol, ~XC_SE);
|
||||
}
|
||||
|
||||
bool
|
||||
dma_txsuspended(dma_info_t *di)
|
||||
{
|
||||
if (!(R_REG(&di->regs->xmtcontrol) & XC_SE))
|
||||
return 0;
|
||||
|
||||
if ((R_REG(&di->regs->xmtstatus) & XS_XS_MASK) != XS_XS_IDLE)
|
||||
return 0;
|
||||
|
||||
OSL_DELAY(2);
|
||||
return ((R_REG(&di->regs->xmtstatus) & XS_XS_MASK) == XS_XS_IDLE);
|
||||
}
|
||||
|
||||
bool
|
||||
dma_txstopped(dma_info_t *di)
|
||||
{
|
||||
return ((R_REG(&di->regs->xmtstatus) & XS_XS_MASK) == XS_XS_STOPPED);
|
||||
}
|
||||
|
||||
bool
|
||||
dma_rxstopped(dma_info_t *di)
|
||||
{
|
||||
return ((R_REG(&di->regs->rcvstatus) & RS_RS_MASK) == RS_RS_STOPPED);
|
||||
}
|
||||
|
||||
void
|
||||
dma_fifoloopbackenable(dma_info_t *di)
|
||||
{
|
||||
DMA_TRACE(("%s: dma_fifoloopbackenable\n", di->name));
|
||||
OR_REG(&di->regs->xmtcontrol, XC_LE);
|
||||
}
|
||||
|
||||
void
|
||||
dma_rxinit(dma_info_t *di)
|
||||
{
|
||||
DMA_TRACE(("%s: dma_rxinit\n", di->name));
|
||||
|
||||
di->rxin = di->rxout = 0;
|
||||
|
||||
/* clear rx descriptor ring */
|
||||
BZERO_SM((void*)di->rxd, (di->nrxd * sizeof (dmadd_t)));
|
||||
|
||||
dma_rxenable(di);
|
||||
W_REG(&di->regs->rcvaddr, (di->rxdpa + di->ddoffset));
|
||||
}
|
||||
|
||||
void
|
||||
dma_rxenable(dma_info_t *di)
|
||||
{
|
||||
DMA_TRACE(("%s: dma_rxenable\n", di->name));
|
||||
W_REG(&di->regs->rcvcontrol, ((di->rxoffset << RC_RO_SHIFT) | RC_RE));
|
||||
}
|
||||
|
||||
bool
|
||||
dma_rxenabled(dma_info_t *di)
|
||||
{
|
||||
uint32 rc;
|
||||
|
||||
rc = R_REG(&di->regs->rcvcontrol);
|
||||
return ((rc != 0xffffffff) && (rc & RC_RE));
|
||||
}
|
||||
|
||||
/*
|
||||
* The BCM47XX family supports full 32bit dma engine buffer addressing so
|
||||
* dma buffers can cross 4 Kbyte page boundaries.
|
||||
*/
|
||||
int
|
||||
dma_txfast(dma_info_t *di, void *p0, uint32 coreflags)
|
||||
{
|
||||
void *p, *next;
|
||||
uchar *data;
|
||||
uint len;
|
||||
uint txout;
|
||||
uint32 ctrl;
|
||||
uint32 pa;
|
||||
|
||||
DMA_TRACE(("%s: dma_txfast\n", di->name));
|
||||
|
||||
txout = di->txout;
|
||||
ctrl = 0;
|
||||
|
||||
/*
|
||||
* Walk the chain of packet buffers
|
||||
* allocating and initializing transmit descriptor entries.
|
||||
*/
|
||||
for (p = p0; p; p = next) {
|
||||
data = PKTDATA(di->drv, p);
|
||||
len = PKTLEN(di->drv, p);
|
||||
next = PKTNEXT(di->drv, p);
|
||||
|
||||
/* return nonzero if out of tx descriptors */
|
||||
if (NEXTTXD(txout) == di->txin)
|
||||
goto outoftxd;
|
||||
|
||||
if (len == 0)
|
||||
continue;
|
||||
|
||||
/* get physical address of buffer start */
|
||||
pa = (uint32) DMA_MAP(di->dev, data, len, DMA_TX, p);
|
||||
|
||||
/* build the descriptor control value */
|
||||
ctrl = len & CTRL_BC_MASK;
|
||||
|
||||
ctrl |= coreflags;
|
||||
|
||||
if (p == p0)
|
||||
ctrl |= CTRL_SOF;
|
||||
if (next == NULL)
|
||||
ctrl |= (CTRL_IOC | CTRL_EOF);
|
||||
if (txout == (di->ntxd - 1))
|
||||
ctrl |= CTRL_EOT;
|
||||
|
||||
/* init the tx descriptor */
|
||||
W_SM(&di->txd[txout].ctrl, BUS_SWAP32(ctrl));
|
||||
W_SM(&di->txd[txout].addr, BUS_SWAP32(pa + di->dataoffset));
|
||||
|
||||
ASSERT(di->txp[txout] == NULL);
|
||||
|
||||
txout = NEXTTXD(txout);
|
||||
}
|
||||
|
||||
/* if last txd eof not set, fix it */
|
||||
if (!(ctrl & CTRL_EOF))
|
||||
W_SM(&di->txd[PREVTXD(txout)].ctrl, BUS_SWAP32(ctrl | CTRL_IOC | CTRL_EOF));
|
||||
|
||||
/* save the packet */
|
||||
di->txp[PREVTXD(txout)] = p0;
|
||||
|
||||
/* bump the tx descriptor index */
|
||||
di->txout = txout;
|
||||
|
||||
/* kick the chip */
|
||||
W_REG(&di->regs->xmtptr, I2B(txout));
|
||||
|
||||
/* tx flow control */
|
||||
di->txavail = di->ntxd - NTXDACTIVE(di->txin, di->txout) - 1;
|
||||
|
||||
return (0);
|
||||
|
||||
outoftxd:
|
||||
DMA_ERROR(("%s: dma_txfast: out of txds\n", di->name));
|
||||
PKTFREE(di->drv, p0, TRUE);
|
||||
di->txavail = 0;
|
||||
di->hnddma.txnobuf++;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
#define PAGESZ 4096
|
||||
#define PAGEBASE(x) ((uint)(x) & ~4095)
|
||||
|
||||
/*
|
||||
* Just like above except go through the extra effort of splitting
|
||||
* buffers that cross 4Kbyte boundaries into multiple tx descriptors.
|
||||
*/
|
||||
int
|
||||
dma_tx(dma_info_t *di, void *p0, uint32 coreflags)
|
||||
{
|
||||
void *p, *next;
|
||||
uchar *data;
|
||||
uint plen, len;
|
||||
uchar *page, *start, *end;
|
||||
uint txout;
|
||||
uint32 ctrl;
|
||||
uint32 pa;
|
||||
|
||||
DMA_TRACE(("%s: dma_tx\n", di->name));
|
||||
|
||||
txout = di->txout;
|
||||
ctrl = 0;
|
||||
|
||||
/*
|
||||
* Walk the chain of packet buffers
|
||||
* splitting those that cross 4 Kbyte boundaries
|
||||
* allocating and initializing transmit descriptor entries.
|
||||
*/
|
||||
for (p = p0; p; p = next) {
|
||||
data = PKTDATA(di->drv, p);
|
||||
plen = PKTLEN(di->drv, p);
|
||||
next = PKTNEXT(di->drv, p);
|
||||
|
||||
if (plen == 0)
|
||||
continue;
|
||||
|
||||
for (page = (uchar*)PAGEBASE(data);
|
||||
page <= (uchar*)PAGEBASE(data + plen - 1);
|
||||
page += PAGESZ) {
|
||||
|
||||
/* return nonzero if out of tx descriptors */
|
||||
if (NEXTTXD(txout) == di->txin)
|
||||
goto outoftxd;
|
||||
|
||||
start = (page == (uchar*)PAGEBASE(data))? data: page;
|
||||
end = (page == (uchar*)PAGEBASE(data + plen))?
|
||||
(data + plen): (page + PAGESZ);
|
||||
len = end - start;
|
||||
|
||||
/* build the descriptor control value */
|
||||
ctrl = len & CTRL_BC_MASK;
|
||||
|
||||
ctrl |= coreflags;
|
||||
|
||||
if ((p == p0) && (start == data))
|
||||
ctrl |= CTRL_SOF;
|
||||
if ((next == NULL) && (end == (data + plen)))
|
||||
ctrl |= (CTRL_IOC | CTRL_EOF);
|
||||
if (txout == (di->ntxd - 1))
|
||||
ctrl |= CTRL_EOT;
|
||||
|
||||
/* get physical address of buffer start */
|
||||
pa = (uint32) DMA_MAP(di->dev, start, len, DMA_TX, p);
|
||||
|
||||
/* init the tx descriptor */
|
||||
W_SM(&di->txd[txout].ctrl, BUS_SWAP32(ctrl));
|
||||
W_SM(&di->txd[txout].addr, BUS_SWAP32(pa + di->dataoffset));
|
||||
|
||||
ASSERT(di->txp[txout] == NULL);
|
||||
|
||||
txout = NEXTTXD(txout);
|
||||
}
|
||||
}
|
||||
|
||||
/* if last txd eof not set, fix it */
|
||||
if (!(ctrl & CTRL_EOF))
|
||||
W_SM(&di->txd[PREVTXD(txout)].ctrl, BUS_SWAP32(ctrl | CTRL_IOC | CTRL_EOF));
|
||||
|
||||
/* save the packet */
|
||||
di->txp[PREVTXD(txout)] = p0;
|
||||
|
||||
/* bump the tx descriptor index */
|
||||
di->txout = txout;
|
||||
|
||||
/* kick the chip */
|
||||
W_REG(&di->regs->xmtptr, I2B(txout));
|
||||
|
||||
/* tx flow control */
|
||||
di->txavail = di->ntxd - NTXDACTIVE(di->txin, di->txout) - 1;
|
||||
|
||||
return (0);
|
||||
|
||||
outoftxd:
|
||||
DMA_ERROR(("%s: dma_tx: out of txds\n", di->name));
|
||||
PKTFREE(di->drv, p0, TRUE);
|
||||
di->txavail = 0;
|
||||
di->hnddma.txnobuf++;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* returns a pointer to the next frame received, or NULL if there are no more */
|
||||
void*
|
||||
dma_rx(dma_info_t *di)
|
||||
{
|
||||
void *p;
|
||||
uint len;
|
||||
int skiplen = 0;
|
||||
|
||||
while ((p = dma_getnextrxp(di, FALSE))) {
|
||||
/* skip giant packets which span multiple rx descriptors */
|
||||
if (skiplen > 0) {
|
||||
skiplen -= di->rxbufsize;
|
||||
if (skiplen < 0)
|
||||
skiplen = 0;
|
||||
PKTFREE(di->drv, p, FALSE);
|
||||
continue;
|
||||
}
|
||||
|
||||
len = ltoh16(*(uint16*)(PKTDATA(di->drv, p)));
|
||||
DMA_TRACE(("%s: dma_rx len %d\n", di->name, len));
|
||||
|
||||
/* bad frame length check */
|
||||
if (len > (di->rxbufsize - di->rxoffset)) {
|
||||
DMA_ERROR(("%s: dma_rx: bad frame length (%d)\n", di->name, len));
|
||||
if (len > 0)
|
||||
skiplen = len - (di->rxbufsize - di->rxoffset);
|
||||
PKTFREE(di->drv, p, FALSE);
|
||||
di->hnddma.rxgiants++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* set actual length */
|
||||
PKTSETLEN(di->drv, p, (di->rxoffset + len));
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return (p);
|
||||
}
|
||||
|
||||
/* post receive buffers */
|
||||
void
|
||||
dma_rxfill(dma_info_t *di)
|
||||
{
|
||||
void *p;
|
||||
uint rxin, rxout;
|
||||
uint ctrl;
|
||||
uint n;
|
||||
uint i;
|
||||
uint32 pa;
|
||||
uint rxbufsize;
|
||||
|
||||
/*
|
||||
* Determine how many receive buffers we're lacking
|
||||
* from the full complement, allocate, initialize,
|
||||
* and post them, then update the chip rx lastdscr.
|
||||
*/
|
||||
|
||||
rxin = di->rxin;
|
||||
rxout = di->rxout;
|
||||
rxbufsize = di->rxbufsize;
|
||||
|
||||
n = di->nrxpost - NRXDACTIVE(rxin, rxout);
|
||||
|
||||
DMA_TRACE(("%s: dma_rxfill: post %d\n", di->name, n));
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
if ((p = PKTGET(di->drv, rxbufsize, FALSE)) == NULL) {
|
||||
DMA_ERROR(("%s: dma_rxfill: out of rxbufs\n", di->name));
|
||||
di->hnddma.rxnobuf++;
|
||||
break;
|
||||
}
|
||||
|
||||
*(uint32*)(OSL_UNCACHED(PKTDATA(di->drv, p))) = 0;
|
||||
|
||||
pa = (uint32) DMA_MAP(di->dev, PKTDATA(di->drv, p), rxbufsize, DMA_RX, p);
|
||||
ASSERT(ISALIGNED(pa, 4));
|
||||
|
||||
/* save the free packet pointer */
|
||||
ASSERT(di->rxp[rxout] == NULL);
|
||||
di->rxp[rxout] = p;
|
||||
|
||||
/* prep the descriptor control value */
|
||||
ctrl = rxbufsize;
|
||||
if (rxout == (di->nrxd - 1))
|
||||
ctrl |= CTRL_EOT;
|
||||
|
||||
/* init the rx descriptor */
|
||||
W_SM(&di->rxd[rxout].ctrl, BUS_SWAP32(ctrl));
|
||||
W_SM(&di->rxd[rxout].addr, BUS_SWAP32(pa + di->dataoffset));
|
||||
|
||||
rxout = NEXTRXD(rxout);
|
||||
}
|
||||
|
||||
di->rxout = rxout;
|
||||
|
||||
/* update the chip lastdscr pointer */
|
||||
W_REG(&di->regs->rcvptr, I2B(rxout));
|
||||
}
|
||||
|
||||
void
|
||||
dma_txreclaim(dma_info_t *di, bool forceall)
|
||||
{
|
||||
void *p;
|
||||
|
||||
DMA_TRACE(("%s: dma_txreclaim %s\n", di->name, forceall ? "all" : ""));
|
||||
|
||||
while ((p = dma_getnexttxp(di, forceall)))
|
||||
PKTFREE(di->drv, p, TRUE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Reclaim next completed txd (txds if using chained buffers) and
|
||||
* return associated packet.
|
||||
* If 'force' is true, reclaim txd(s) and return associated packet
|
||||
* regardless of the value of the hardware "curr" pointer.
|
||||
*/
|
||||
void*
|
||||
dma_getnexttxp(dma_info_t *di, bool forceall)
|
||||
{
|
||||
uint start, end, i;
|
||||
void *txp;
|
||||
|
||||
DMA_TRACE(("%s: dma_getnexttxp %s\n", di->name, forceall ? "all" : ""));
|
||||
|
||||
txp = NULL;
|
||||
|
||||
start = di->txin;
|
||||
if (forceall)
|
||||
end = di->txout;
|
||||
else
|
||||
end = B2I(R_REG(&di->regs->xmtstatus) & XS_CD_MASK);
|
||||
|
||||
if ((start == 0) && (end > di->txout))
|
||||
goto bogus;
|
||||
|
||||
for (i = start; i != end && !txp; i = NEXTTXD(i)) {
|
||||
DMA_UNMAP(di->dev, (BUS_SWAP32(R_SM(&di->txd[i].addr)) - di->dataoffset),
|
||||
(BUS_SWAP32(R_SM(&di->txd[i].ctrl)) & CTRL_BC_MASK), DMA_TX, di->txp[i]);
|
||||
W_SM(&di->txd[i].addr, 0xdeadbeef);
|
||||
txp = di->txp[i];
|
||||
di->txp[i] = NULL;
|
||||
}
|
||||
|
||||
di->txin = i;
|
||||
|
||||
/* tx flow control */
|
||||
di->txavail = di->ntxd - NTXDACTIVE(di->txin, di->txout) - 1;
|
||||
|
||||
return (txp);
|
||||
|
||||
bogus:
|
||||
/*
|
||||
DMA_ERROR(("dma_getnexttxp: bogus curr: start %d end %d txout %d force %d\n",
|
||||
start, end, di->txout, forceall));
|
||||
*/
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* like getnexttxp but no reclaim */
|
||||
void*
|
||||
dma_peeknexttxp(dma_info_t *di)
|
||||
{
|
||||
uint end, i;
|
||||
|
||||
end = B2I(R_REG(&di->regs->xmtstatus) & XS_CD_MASK);
|
||||
|
||||
for (i = di->txin; i != end; i = NEXTTXD(i))
|
||||
if (di->txp[i])
|
||||
return (di->txp[i]);
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
void
|
||||
dma_rxreclaim(dma_info_t *di)
|
||||
{
|
||||
void *p;
|
||||
|
||||
DMA_TRACE(("%s: dma_rxreclaim\n", di->name));
|
||||
|
||||
while ((p = dma_getnextrxp(di, TRUE)))
|
||||
PKTFREE(di->drv, p, FALSE);
|
||||
}
|
||||
|
||||
void *
|
||||
dma_getnextrxp(dma_info_t *di, bool forceall)
|
||||
{
|
||||
uint i;
|
||||
void *rxp;
|
||||
|
||||
/* if forcing, dma engine must be disabled */
|
||||
ASSERT(!forceall || !dma_rxenabled(di));
|
||||
|
||||
i = di->rxin;
|
||||
|
||||
/* return if no packets posted */
|
||||
if (i == di->rxout)
|
||||
return (NULL);
|
||||
|
||||
/* ignore curr if forceall */
|
||||
if (!forceall && (i == B2I(R_REG(&di->regs->rcvstatus) & RS_CD_MASK)))
|
||||
return (NULL);
|
||||
|
||||
/* get the packet pointer that corresponds to the rx descriptor */
|
||||
rxp = di->rxp[i];
|
||||
ASSERT(rxp);
|
||||
di->rxp[i] = NULL;
|
||||
|
||||
/* clear this packet from the descriptor ring */
|
||||
DMA_UNMAP(di->dev, (BUS_SWAP32(R_SM(&di->rxd[i].addr)) - di->dataoffset),
|
||||
di->rxbufsize, DMA_RX, rxp);
|
||||
W_SM(&di->rxd[i].addr, 0xdeadbeef);
|
||||
|
||||
di->rxin = NEXTRXD(i);
|
||||
|
||||
return (rxp);
|
||||
}
|
||||
|
||||
char*
|
||||
dma_dumptx(dma_info_t *di, char *buf)
|
||||
{
|
||||
buf += sprintf(buf, "txd 0x%lx txdpa 0x%lx txp 0x%lx txin %d txout %d txavail %d\n",
|
||||
(ulong)di->txd, di->txdpa, (ulong)di->txp, di->txin, di->txout, di->txavail);
|
||||
buf += sprintf(buf, "xmtcontrol 0x%x xmtaddr 0x%x xmtptr 0x%x xmtstatus 0x%x\n",
|
||||
R_REG(&di->regs->xmtcontrol),
|
||||
R_REG(&di->regs->xmtaddr),
|
||||
R_REG(&di->regs->xmtptr),
|
||||
R_REG(&di->regs->xmtstatus));
|
||||
return (buf);
|
||||
}
|
||||
|
||||
char*
|
||||
dma_dumprx(dma_info_t *di, char *buf)
|
||||
{
|
||||
buf += sprintf(buf, "rxd 0x%lx rxdpa 0x%lx rxp 0x%lx rxin %d rxout %d\n",
|
||||
(ulong)di->rxd, di->rxdpa, (ulong)di->rxp, di->rxin, di->rxout);
|
||||
buf += sprintf(buf, "rcvcontrol 0x%x rcvaddr 0x%x rcvptr 0x%x rcvstatus 0x%x\n",
|
||||
R_REG(&di->regs->rcvcontrol),
|
||||
R_REG(&di->regs->rcvaddr),
|
||||
R_REG(&di->regs->rcvptr),
|
||||
R_REG(&di->regs->rcvstatus));
|
||||
return (buf);
|
||||
}
|
||||
|
||||
char*
|
||||
dma_dump(dma_info_t *di, char *buf)
|
||||
{
|
||||
buf = dma_dumptx(di, buf);
|
||||
buf = dma_dumprx(di, buf);
|
||||
return (buf);
|
||||
}
|
||||
|
||||
uint
|
||||
dma_getvar(dma_info_t *di, char *name)
|
||||
{
|
||||
if (!strcmp(name, "&txavail"))
|
||||
return ((uint) &di->txavail);
|
||||
else {
|
||||
ASSERT(0);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
dma_txblock(dma_info_t *di)
|
||||
{
|
||||
di->txavail = 0;
|
||||
}
|
||||
|
||||
void
|
||||
dma_txunblock(dma_info_t *di)
|
||||
{
|
||||
di->txavail = di->ntxd - NTXDACTIVE(di->txin, di->txout) - 1;
|
||||
}
|
||||
|
||||
uint
|
||||
dma_txactive(dma_info_t *di)
|
||||
{
|
||||
return (NTXDACTIVE(di->txin, di->txout));
|
||||
}
|
||||
|
||||
/*
|
||||
* Rotate all active tx dma ring entries "forward" by (ActiveDescriptor - txin).
|
||||
*/
|
||||
void
|
||||
dma_txrotate(di_t *di)
|
||||
{
|
||||
uint ad;
|
||||
uint nactive;
|
||||
uint rot;
|
||||
uint old, new;
|
||||
uint32 w;
|
||||
uint first, last;
|
||||
|
||||
ASSERT(dma_txsuspended(di));
|
||||
|
||||
nactive = dma_txactive(di);
|
||||
ad = B2I((R_REG(&di->regs->xmtstatus) & XS_AD_MASK) >> XS_AD_SHIFT);
|
||||
rot = TXD(ad - di->txin);
|
||||
|
||||
ASSERT(rot < di->ntxd);
|
||||
|
||||
/* full-ring case is a lot harder - don't worry about this */
|
||||
if (rot >= (di->ntxd - nactive)) {
|
||||
DMA_ERROR(("%s: dma_txrotate: ring full - punt\n", di->name));
|
||||
return;
|
||||
}
|
||||
|
||||
first = di->txin;
|
||||
last = PREVTXD(di->txout);
|
||||
|
||||
/* move entries starting at last and moving backwards to first */
|
||||
for (old = last; old != PREVTXD(first); old = PREVTXD(old)) {
|
||||
new = TXD(old + rot);
|
||||
|
||||
/*
|
||||
* Move the tx dma descriptor.
|
||||
* EOT is set only in the last entry in the ring.
|
||||
*/
|
||||
w = R_SM(&di->txd[old].ctrl) & ~CTRL_EOT;
|
||||
if (new == (di->ntxd - 1))
|
||||
w |= CTRL_EOT;
|
||||
W_SM(&di->txd[new].ctrl, w);
|
||||
W_SM(&di->txd[new].addr, R_SM(&di->txd[old].addr));
|
||||
|
||||
/* zap the old tx dma descriptor address field */
|
||||
W_SM(&di->txd[old].addr, 0xdeadbeef);
|
||||
|
||||
/* move the corresponding txp[] entry */
|
||||
ASSERT(di->txp[new] == NULL);
|
||||
di->txp[new] = di->txp[old];
|
||||
di->txp[old] = NULL;
|
||||
}
|
||||
|
||||
/* update txin and txout */
|
||||
di->txin = ad;
|
||||
di->txout = TXD(di->txout + rot);
|
||||
di->txavail = di->ntxd - NTXDACTIVE(di->txin, di->txout) - 1;
|
||||
|
||||
/* kick the chip */
|
||||
W_REG(&di->regs->xmtptr, I2B(di->txout));
|
||||
}
|
||||
465
package/linux/kernel-source/drivers/net/hnd/linux_osl.c
Normal file
465
package/linux/kernel-source/drivers/net/hnd/linux_osl.c
Normal file
@@ -0,0 +1,465 @@
|
||||
/*
|
||||
* Linux OS Independent Layer
|
||||
*
|
||||
* Copyright 2004, Broadcom Corporation
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
|
||||
* KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
|
||||
* SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#define LINUX_OSL
|
||||
|
||||
#include <typedefs.h>
|
||||
#include <bcmendian.h>
|
||||
#include <linuxver.h>
|
||||
#include <linux_osl.h>
|
||||
#include <bcmutils.h>
|
||||
#include <linux/delay.h>
|
||||
#ifdef mips
|
||||
#include <asm/paccess.h>
|
||||
#endif
|
||||
#include <pcicfg.h>
|
||||
|
||||
#define PCI_CFG_RETRY 10
|
||||
|
||||
void*
|
||||
osl_pktget(void *drv, uint len, bool send)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
|
||||
if ((skb = dev_alloc_skb(len)) == NULL)
|
||||
return (NULL);
|
||||
|
||||
skb_put(skb, len);
|
||||
|
||||
/* ensure the cookie field is cleared */
|
||||
PKTSETCOOKIE(skb, NULL);
|
||||
|
||||
return ((void*) skb);
|
||||
}
|
||||
|
||||
void
|
||||
osl_pktfree(void *p)
|
||||
{
|
||||
struct sk_buff *skb, *nskb;
|
||||
|
||||
skb = (struct sk_buff*) p;
|
||||
|
||||
/* perversion: we use skb->next to chain multi-skb packets */
|
||||
while (skb) {
|
||||
nskb = skb->next;
|
||||
skb->next = NULL;
|
||||
if (skb->destructor) {
|
||||
/* cannot kfree_skb() on hard IRQ (net/core/skbuff.c) if destructor exists */
|
||||
dev_kfree_skb_any(skb);
|
||||
} else {
|
||||
/* can free immediately (even in_irq()) if destructor does not exist */
|
||||
dev_kfree_skb(skb);
|
||||
}
|
||||
skb = nskb;
|
||||
}
|
||||
}
|
||||
|
||||
uint32
|
||||
osl_pci_read_config(void *loc, uint offset, uint size)
|
||||
{
|
||||
struct pci_dev *pdev;
|
||||
uint val;
|
||||
uint retry=PCI_CFG_RETRY;
|
||||
|
||||
/* only 4byte access supported */
|
||||
ASSERT(size == 4);
|
||||
|
||||
pdev = (struct pci_dev*)loc;
|
||||
do {
|
||||
pci_read_config_dword(pdev, offset, &val);
|
||||
if (val != 0xffffffff)
|
||||
break;
|
||||
} while (retry--);
|
||||
|
||||
|
||||
return (val);
|
||||
}
|
||||
|
||||
void
|
||||
osl_pci_write_config(void *loc, uint offset, uint size, uint val)
|
||||
{
|
||||
struct pci_dev *pdev;
|
||||
uint retry=PCI_CFG_RETRY;
|
||||
|
||||
/* only 4byte access supported */
|
||||
ASSERT(size == 4);
|
||||
|
||||
pdev = (struct pci_dev*)loc;
|
||||
|
||||
do {
|
||||
pci_write_config_dword(pdev, offset, val);
|
||||
if (offset!=PCI_BAR0_WIN)
|
||||
break;
|
||||
if (osl_pci_read_config(loc,offset,size) == val)
|
||||
break;
|
||||
} while (retry--);
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
osl_pcmcia_attr(void *osh, uint offset, char *buf, int size, bool write)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
osl_pcmcia_read_attr(void *osh, uint offset, void *buf, int size)
|
||||
{
|
||||
osl_pcmcia_attr(osh, offset, (char *) buf, size, FALSE);
|
||||
}
|
||||
|
||||
void
|
||||
osl_pcmcia_write_attr(void *osh, uint offset, void *buf, int size)
|
||||
{
|
||||
osl_pcmcia_attr(osh, offset, (char *) buf, size, TRUE);
|
||||
}
|
||||
|
||||
#if defined(BINOSL)
|
||||
|
||||
void
|
||||
osl_assert(char *exp, char *file, int line)
|
||||
{
|
||||
char tempbuf[255];
|
||||
|
||||
sprintf(tempbuf, "assertion \"%s\" failed: file \"%s\", line %d\n", exp, file, line);
|
||||
panic(tempbuf);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void*
|
||||
osl_malloc(uint size)
|
||||
{
|
||||
return (kmalloc(size, GFP_ATOMIC));
|
||||
}
|
||||
|
||||
void
|
||||
osl_mfree(void *addr, uint size)
|
||||
{
|
||||
kfree(addr);
|
||||
}
|
||||
|
||||
uint
|
||||
osl_malloced(void)
|
||||
{
|
||||
#ifdef MODULE
|
||||
return malloced;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* defined(BCMDBG) || defined(BINOSL) */
|
||||
|
||||
/*
|
||||
* BINOSL selects the slightly slower function-call-based binary compatible osl.
|
||||
*/
|
||||
#ifdef BINOSL
|
||||
|
||||
int
|
||||
osl_printf(const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
char buf[1024];
|
||||
int len;
|
||||
|
||||
/* sprintf into a local buffer because there *is* no "vprintk()".. */
|
||||
va_start(args, format);
|
||||
len = vsprintf(buf, format, args);
|
||||
va_end(args);
|
||||
|
||||
if (len > sizeof (buf)) {
|
||||
printk("osl_printf: buffer overrun\n");
|
||||
return (0);
|
||||
}
|
||||
|
||||
return (printk(buf));
|
||||
}
|
||||
|
||||
int
|
||||
osl_sprintf(char *buf, const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
int rc;
|
||||
|
||||
va_start(args, format);
|
||||
rc = vsprintf(buf, format, args);
|
||||
va_end(args);
|
||||
return (rc);
|
||||
}
|
||||
|
||||
int
|
||||
osl_strcmp(const char *s1, const char *s2)
|
||||
{
|
||||
return (strcmp(s1, s2));
|
||||
}
|
||||
|
||||
int
|
||||
osl_strncmp(const char *s1, const char *s2, uint n)
|
||||
{
|
||||
return (strncmp(s1, s2, n));
|
||||
}
|
||||
|
||||
int
|
||||
osl_strlen(char *s)
|
||||
{
|
||||
return (strlen(s));
|
||||
}
|
||||
|
||||
char*
|
||||
osl_strcpy(char *d, const char *s)
|
||||
{
|
||||
return (strcpy(d, s));
|
||||
}
|
||||
|
||||
char*
|
||||
osl_strncpy(char *d, const char *s, uint n)
|
||||
{
|
||||
return (strncpy(d, s, n));
|
||||
}
|
||||
|
||||
void
|
||||
bcopy(const void *src, void *dst, int len)
|
||||
{
|
||||
memcpy(dst, src, len);
|
||||
}
|
||||
|
||||
int
|
||||
bcmp(const void *b1, const void *b2, int len)
|
||||
{
|
||||
return (memcmp(b1, b2, len));
|
||||
}
|
||||
|
||||
void
|
||||
bzero(void *b, int len)
|
||||
{
|
||||
memset(b, '\0', len);
|
||||
}
|
||||
|
||||
uint32
|
||||
osl_readl(volatile uint32 *r)
|
||||
{
|
||||
return (readl(r));
|
||||
}
|
||||
|
||||
uint16
|
||||
osl_readw(volatile uint16 *r)
|
||||
{
|
||||
return (readw(r));
|
||||
}
|
||||
|
||||
uint8
|
||||
osl_readb(volatile uint8 *r)
|
||||
{
|
||||
return (readb(r));
|
||||
}
|
||||
|
||||
void
|
||||
osl_writel(uint32 v, volatile uint32 *r)
|
||||
{
|
||||
writel(v, r);
|
||||
}
|
||||
|
||||
void
|
||||
osl_writew(uint16 v, volatile uint16 *r)
|
||||
{
|
||||
writew(v, r);
|
||||
}
|
||||
|
||||
void
|
||||
osl_writeb(uint8 v, volatile uint8 *r)
|
||||
{
|
||||
writeb(v, r);
|
||||
}
|
||||
|
||||
void *
|
||||
osl_uncached(void *va)
|
||||
{
|
||||
#ifdef mips
|
||||
return ((void*)KSEG1ADDR(va));
|
||||
#else
|
||||
return ((void*)va);
|
||||
#endif
|
||||
}
|
||||
|
||||
uint
|
||||
osl_getcycles(void)
|
||||
{
|
||||
uint cycles;
|
||||
|
||||
#if defined(mips)
|
||||
cycles = read_c0_count() * 2;
|
||||
#elif defined(__i386__)
|
||||
rdtscl(cycles);
|
||||
#else
|
||||
cycles = 0;
|
||||
#endif
|
||||
return cycles;
|
||||
}
|
||||
|
||||
void *
|
||||
osl_reg_map(uint32 pa, uint size)
|
||||
{
|
||||
return (ioremap_nocache((unsigned long)pa, (unsigned long)size));
|
||||
}
|
||||
|
||||
void
|
||||
osl_reg_unmap(void *va)
|
||||
{
|
||||
iounmap(va);
|
||||
}
|
||||
|
||||
int
|
||||
osl_busprobe(uint32 *val, uint32 addr)
|
||||
{
|
||||
#ifdef mips
|
||||
return get_dbe(*val, (uint32*)addr);
|
||||
#else
|
||||
*val = readl(addr);
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void*
|
||||
osl_dma_alloc_consistent(void *dev, uint size, ulong *pap)
|
||||
{
|
||||
return (pci_alloc_consistent((struct pci_dev*)dev, size, (dma_addr_t*)pap));
|
||||
}
|
||||
|
||||
void
|
||||
osl_dma_free_consistent(void *dev, void *va, uint size, ulong pa)
|
||||
{
|
||||
pci_free_consistent((struct pci_dev*)dev, size, va, (dma_addr_t)pa);
|
||||
}
|
||||
|
||||
uint
|
||||
osl_dma_map(void *dev, void *va, uint size, int direction)
|
||||
{
|
||||
int dir;
|
||||
|
||||
dir = (direction == DMA_TX)? PCI_DMA_TODEVICE: PCI_DMA_FROMDEVICE;
|
||||
return (pci_map_single(dev, va, size, dir));
|
||||
}
|
||||
|
||||
void
|
||||
osl_dma_unmap(void *dev, uint pa, uint size, int direction)
|
||||
{
|
||||
int dir;
|
||||
|
||||
dir = (direction == DMA_TX)? PCI_DMA_TODEVICE: PCI_DMA_FROMDEVICE;
|
||||
pci_unmap_single(dev, (uint32)pa, size, dir);
|
||||
}
|
||||
|
||||
void
|
||||
osl_delay(uint usec)
|
||||
{
|
||||
udelay(usec);
|
||||
}
|
||||
|
||||
uchar*
|
||||
osl_pktdata(void *drv, void *skb)
|
||||
{
|
||||
return (((struct sk_buff*)skb)->data);
|
||||
}
|
||||
|
||||
uint
|
||||
osl_pktlen(void *drv, void *skb)
|
||||
{
|
||||
return (((struct sk_buff*)skb)->len);
|
||||
}
|
||||
|
||||
uint
|
||||
osl_pktheadroom(void *drv, void *skb)
|
||||
{
|
||||
return (uint) skb_headroom((struct sk_buff *) skb);
|
||||
}
|
||||
|
||||
uint
|
||||
osl_pkttailroom(void *drv, void *skb)
|
||||
{
|
||||
return (uint) skb_tailroom((struct sk_buff *) skb);
|
||||
}
|
||||
|
||||
void*
|
||||
osl_pktnext(void *drv, void *skb)
|
||||
{
|
||||
return (((struct sk_buff*)skb)->next);
|
||||
}
|
||||
|
||||
void
|
||||
osl_pktsetnext(void *skb, void *x)
|
||||
{
|
||||
((struct sk_buff*)skb)->next = (struct sk_buff*)x;
|
||||
}
|
||||
|
||||
void
|
||||
osl_pktsetlen(void *drv, void *skb, uint len)
|
||||
{
|
||||
__skb_trim((struct sk_buff*)skb, len);
|
||||
}
|
||||
|
||||
uchar*
|
||||
osl_pktpush(void *drv, void *skb, int bytes)
|
||||
{
|
||||
return (skb_push((struct sk_buff*)skb, bytes));
|
||||
}
|
||||
|
||||
uchar*
|
||||
osl_pktpull(void *drv, void *skb, int bytes)
|
||||
{
|
||||
return (skb_pull((struct sk_buff*)skb, bytes));
|
||||
}
|
||||
|
||||
void*
|
||||
osl_pktdup(void *drv, void *skb)
|
||||
{
|
||||
return (skb_clone((struct sk_buff*)skb, GFP_ATOMIC));
|
||||
}
|
||||
|
||||
void*
|
||||
osl_pktcookie(void *skb)
|
||||
{
|
||||
return ((void*)((struct sk_buff*)skb)->csum);
|
||||
}
|
||||
|
||||
void
|
||||
osl_pktsetcookie(void *skb, void *x)
|
||||
{
|
||||
((struct sk_buff*)skb)->csum = (uint)x;
|
||||
}
|
||||
|
||||
void*
|
||||
osl_pktlink(void *skb)
|
||||
{
|
||||
return (((struct sk_buff*)skb)->prev);
|
||||
}
|
||||
|
||||
void
|
||||
osl_pktsetlink(void *skb, void *x)
|
||||
{
|
||||
((struct sk_buff*)skb)->prev = (struct sk_buff*)x;
|
||||
}
|
||||
|
||||
uint
|
||||
osl_pktprio(void *skb)
|
||||
{
|
||||
return (((struct sk_buff*)skb)->priority);
|
||||
}
|
||||
|
||||
void
|
||||
osl_pktsetprio(void *skb, uint x)
|
||||
{
|
||||
((struct sk_buff*)skb)->priority = x;
|
||||
}
|
||||
|
||||
#endif /* BINOSL */
|
||||
2164
package/linux/kernel-source/drivers/net/hnd/sbutils.c
Normal file
2164
package/linux/kernel-source/drivers/net/hnd/sbutils.c
Normal file
File diff suppressed because it is too large
Load Diff
21
package/linux/kernel-source/drivers/net/hnd/shared_ksyms.sh
Normal file
21
package/linux/kernel-source/drivers/net/hnd/shared_ksyms.sh
Normal file
@@ -0,0 +1,21 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Copyright 2004, Broadcom Corporation
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
|
||||
# KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
|
||||
# SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
# FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
|
||||
#
|
||||
# $Id$
|
||||
#
|
||||
|
||||
cat <<EOF
|
||||
#include <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
EOF
|
||||
|
||||
for file in $* ; do
|
||||
${NM} $file | sed -ne 's/[0-9A-Fa-f]* [DT] \([^ ]*\)/extern void \1; EXPORT_SYMBOL(\1);/p'
|
||||
done
|
||||
59
package/linux/kernel-source/drivers/net/wl/Makefile
Normal file
59
package/linux/kernel-source/drivers/net/wl/Makefile
Normal file
@@ -0,0 +1,59 @@
|
||||
#
|
||||
# Makefile for the Broadcom wl driver
|
||||
#
|
||||
# Copyright 2004, Broadcom Corporation
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
|
||||
# KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
|
||||
# SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
# FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
|
||||
#
|
||||
# $Id$
|
||||
#
|
||||
|
||||
O_TARGET := wl.o
|
||||
|
||||
WL_OBJS := wl_linux.o wlc.o d11ucode.o wlc_phy.o wlc_rate.o wlc_led.o wlc_security.o rc4.o tkhash.o bcmwpa.o
|
||||
|
||||
INSUP_OBJS := aes.o aeskeywrap.o hmac.o md5.o passhash.o prf.o rijndael-alg-fst.o sha1.o
|
||||
|
||||
# Alternate ioctl interfaces
|
||||
ifeq ($(CONFIG_NET_WIRELESS),y)
|
||||
WL_OBJS += wlc_cmn_ioctl.o
|
||||
endif
|
||||
ifeq ($(CONFIG_WL_OID),y)
|
||||
WL_OBJS += wl_oid.o
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_WL_STA),y)
|
||||
WL_OBJS += $(INSUP_OBJS)
|
||||
endif
|
||||
|
||||
# Prefix driver variants
|
||||
WL_APOBJS := $(foreach obj,$(WL_OBJS),ap_$(obj))
|
||||
WL_STAOBJS := $(foreach obj,$(WL_OBJS) wlc_sup.o,sta_$(obj))
|
||||
WL_APSTAOBJS := $(foreach obj,$(WL_OBJS) wlc_sup.o,apsta_$(obj))
|
||||
ifneq ($(CONFIG_WL_STA),y)
|
||||
WL_APSTAOBJS += $(foreach obj,$(INSUP_OBJS), apsta_$(obj))
|
||||
endif
|
||||
|
||||
# Either or both
|
||||
ifeq ($(CONFIG_WL_AP),y)
|
||||
AP := AP
|
||||
endif
|
||||
ifeq ($(CONFIG_WL_STA),y)
|
||||
STA := STA
|
||||
endif
|
||||
|
||||
# Build all variants as modules but link only one of them
|
||||
export-objs :=
|
||||
obj-y := $(WL_$(AP)$(STA)OBJS)
|
||||
obj-m := $(O_TARGET)
|
||||
variant-objs := $(WL_APOBJS) $(WL_STAOBJS) $(WL_APSTAOBJS)
|
||||
|
||||
EXTRA_CFLAGS += -DDMA
|
||||
|
||||
include $(TOPDIR)/Rules.make
|
||||
|
||||
|
||||
Reference in New Issue
Block a user