Subject: misc cardbus patches
To: None <gnats-bugs@gnats.netbsd.org>
From: Johan Danielsson <joda@pdc.kth.se>
List: netbsd-bugs
Date: 10/15/1999 17:52:47
>Number: 8630
>Category: kern
>Synopsis: misc cardbus patches
>Confidential: no
>Severity: serious
>Priority: high
>Responsible: kern-bug-people (Kernel Bug People)
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Fri Oct 15 23:27:03 1999
>Last-Modified:
>Originator: Johan Danielsson
>Organization:
>Release: 1999-10-15
>Environment:
<machine, os, target, libraries (multiple lines)>
System: NetBSD 1.4L (BLUBB) #9: Fri Oct 15 17:22:11 CEST 1999
>Description:
The CardBus code needs more work. Here are some patches that I need to
do anything useful, they are sent in batch, since some of these
changes are related, and a few are simple bug fixes.
>How-To-Repeat:
Try to use an fxp cardbus card.
>Fix:
The following patch fixes these problems with the cardbus code:
* implement reading memory mapped CIS (via BAR or EXROM), now it only
works with CIS in config space (the guts of this in the
cardbus_read_tuples function)
* it doesn't work with multi function cards (everything required is a
loop for each function, in attach); it requires that sc_poweron_func
is a bitmask of enabled functions, there might be more places this
has to change
* fixes a bug in latency timer calculation
* fixes a typo in Cardbus_conf_write
--- cardbus.c 1999/10/15 06:41:27 1.2
+++ cardbus.c 1999/10/15 15:39:50
@@ -168,9 +168,184 @@
cdstatus = 0;
}
+static unsigned
+cardbus_control(cardbus_devfunc_t ct,
+ unsigned enable,
+ unsigned disable)
+{
+ cardbustag_t tag = cardbus_make_tag(ct->ct_cc, ct->ct_cf, ct->ct_bus,
+ ct->ct_dev, ct->ct_func);
+
+ unsigned status = Cardbus_conf_read(ct, tag, PCI_COMMAND_STATUS_REG);
+ status &= ~disable;
+ status |= enable;
+ Cardbus_conf_write(ct, tag, PCI_COMMAND_STATUS_REG, status);
+ return status;
+}
+
+static int
+cardbus_read_tuples(struct cardbus_attach_args *ca,
+ cardbusreg_t cis_ptr,
+ u_int8_t *tuples,
+ size_t len)
+{
+ cardbus_chipset_tag_t cc = ca->ca_ct->ct_cc;
+ cardbus_function_tag_t cf = ca->ca_ct->ct_cf;
+ cardbustag_t tag = ca->ca_tag;
+ int found = 0;
+
+ int i, j;
+ int cardbus_space = cis_ptr & CARDBUS_CIS_ASIMASK;
+ bus_space_handle_t bar_memh;
+ bus_size_t bar_size;
+ bus_addr_t bar_addr;
+
+ int reg;
+
+ memset(tuples, 0, len);
+
+ cis_ptr = cis_ptr & CARDBUS_CIS_ADDRMASK;
+
+ switch(cardbus_space) {
+ case CARDBUS_CIS_ASI_TUPLE:
+ DPRINTF(("%s: reading CIS data from configuration space\n",
+ __FUNCTION__));
+ for (i = cis_ptr, j = 0; i < 0xff; i += 4) {
+ u_int32_t e = (cf->cardbus_conf_read)(cc, tag, i);
+ tuples[j] = 0xff & e;
+ e >>= 8;
+ tuples[j + 1] = 0xff & e;
+ e >>= 8;
+ tuples[j + 2] = 0xff & e;
+ e >>= 8;
+ tuples[j + 3] = 0xff & e;
+ j += 4;
+ }
+ found++;
+ break;
+ case CARDBUS_CIS_ASI_BAR0:
+ case CARDBUS_CIS_ASI_BAR1:
+ case CARDBUS_CIS_ASI_BAR2:
+ case CARDBUS_CIS_ASI_BAR3:
+ case CARDBUS_CIS_ASI_BAR4:
+ case CARDBUS_CIS_ASI_BAR5:
+ case CARDBUS_CIS_ASI_ROM:
+ if(cardbus_space == CARDBUS_CIS_ASI_ROM) {
+ reg = CARDBUS_ROM_REG;
+ DPRINTF(("%s: reading CIS data from EXROM\n", __FUNCTION__));
+ } else {
+ reg = CARDBUS_BASE0_REG + (cardbus_space - 1) * 4;
+ DPRINTF(("%s: reading CIS data from base address register %d\n",
+ __FUNCTION__, cardbus_space - 1));
+ }
+
+ /* zero register so mapreg_map doesn't get confused by old
+ contents */
+ cardbus_conf_write(cc, cf, tag, reg, 0);
+ if(cardbus_mapreg_map(ca->ca_ct, reg,
+ PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT,
+ 0,
+ NULL, &bar_memh, &bar_addr, &bar_size)) {
+ printf("%s: failed to map memory\n", __FUNCTION__);
+ return 1;
+ }
+
+ /* enable ROM address decoder, this should be a nop if
+ this is a BAR */
+ cardbus_conf_write(cc, cf, tag, reg, bar_addr | 1);
+
+ cardbus_control(ca->ca_ct, PCI_COMMAND_MEM_ENABLE, 0);
+
+ if(cardbus_space == CARDBUS_CIS_ASI_ROM) {
+ int addr = 0;
+ int rom_image = 0;
+ int size;
+ int data;
+
+ /* the rom apparently looks like this:
+ 00: 0x55aa
+ 18: data pointer
+ 00: signature
+ 10: image size (in 512 blocks)
+ 15: indicator?
+ */
+ /* read a 16 bit integer (in lsb byteorder) */
+#define read_int16(tag, handle, addr) \
+ ((bus_space_read_1((tag), (handle), (addr))) | \
+ (bus_space_read_1((tag), (handle), (addr) + 1) << 8))
+
+ while(read_int16(ca->ca_memt, bar_memh, addr) == 0xaa55) {
+ if(rom_image == (cis_ptr >> 28)) {
+ /* if this is the correct rom image, just get the
+ CIS and exit */
+ bus_space_read_region_1(ca->ca_memt, bar_memh,
+ addr + (cis_ptr & 0x0ffffff8),
+ tuples, 256);
+ found++;
+ break;
+ }
+ /* get offset of data structure */
+ data = addr +
+ read_int16(ca->ca_memt, bar_memh, addr + 0x18);
+ /* get image size */
+ size = read_int16(ca->ca_memt, bar_memh, data + 0x10);
+ if(size == 0 ||
+ (bus_space_read_1(ca->ca_memt, bar_memh,
+ data + 0x15) & 0x80))
+ /* this was the last rom image */
+ break;
+ addr += (size << 9);
+ rom_image++;
+ }
+ } else {
+ /* XXX byte order? */
+ bus_space_read_region_1(ca->ca_memt, bar_memh,
+ cis_ptr, tuples, 256);
+ found++;
+ }
+ /* unmap and free memory */
+ cardbus_control(ca->ca_ct, 0, PCI_COMMAND_MEM_ENABLE);
+ cardbus_conf_write(cc, cf, tag, reg, 0);
+#if 0
+ /* XXX unmap memory */
+ (*ca->ca_ct->ct_cf->cardbus_space_free)(ca->ca_ct,
+ ca->ca_ct->ct_sc->sc_rbus_memt,
+ bar_memh, bar_size);
+#endif
+ break;
+
+#ifdef DIAGNOSTIC
+ default:
+ panic("%s: bad CIS space (%d)", __FUNCTION__, cardbus_space);
+#endif
+ }
+ return !found;
+}
+
+static void
+enable_function(struct cardbus_softc *sc, int cdstatus, int function)
+{
+ if(sc->sc_poweron_func == 0) {
+ if (cdstatus & CARDBUS_3V_CARD) {
+ sc->sc_cf->cardbus_power(sc->sc_cc, CARDBUS_VCC_3V);
+ }
+ (sc->sc_cf->cardbus_ctrl)(sc->sc_cc, CARDBUS_RESET);
+ }
+ sc->sc_poweron_func |= (1 << function);
+}
+
+static void
+disable_function(struct cardbus_softc *sc, int function)
+{
+ sc->sc_poweron_func &= ~(1 << function);
+ if(sc->sc_poweron_func == 0) {
+ sc->sc_cf->cardbus_power(sc->sc_cc, CARDBUS_VCC_0V);
+ }
+}
+
/*
* int cardbus_attach_card(struct cardbus_softc *sc)
*
@@ -195,7 +370,6 @@
struct cardbus_devfunc **previous_next = &(sc->sc_funcs);
struct device *csc;
int no_work_funcs = 0;
- cardbus_devfunc_t ct;
cc = sc->sc_cc;
cf = sc->sc_cf;
@@ -207,14 +381,10 @@
DPRINTF(("cardbusattach: no CardBus card on cb%d\n", sc->sc_dev.dv_unit));
return 0;
}
-
- if (cdstatus & CARDBUS_3V_CARD) {
- cf->cardbus_power(cc, CARDBUS_VCC_3V);
- sc->sc_poweron_func = 1; /* function 0 on */
- }
-
- (cf->cardbus_ctrl)(cc, CARDBUS_RESET);
+ enable_function(sc, cdstatus, 8); /* XXX use fake function 8 to
+ keep power on during whole
+ configuration */
function = 0;
tag = cardbus_make_tag(cc, cf, sc->sc_bus, sc->sc_device, function);
@@ -238,55 +408,34 @@
bhlc = cardbus_conf_read(cc, cf, tag, CARDBUS_BHLC_REG);
if (CARDBUS_LATTIMER(bhlc) < 0x10) {
- bhlc &= (CARDBUS_LATTIMER_MASK << CARDBUS_LATTIMER_SHIFT);
+ bhlc &= ~(CARDBUS_LATTIMER_MASK << CARDBUS_LATTIMER_SHIFT);
bhlc |= (0x10 << CARDBUS_LATTIMER_SHIFT);
cardbus_conf_write(cc, cf, tag, CARDBUS_BHLC_REG, bhlc);
}
nfunction = CARDBUS_HDRTYPE_MULTIFN(bhlc) ? 8 : 1;
- /*
- * XXX multi-function card
- *
- * I don't know how to process CIS information for
- * multi-function cards.
- */
+ for(function = 0; function < nfunction; function++) {
+ struct cardbus_attach_args ca;
+ cardbus_devfunc_t ct;
+
+ enable_function(sc, cdstatus, function);
+
+ tag = cardbus_make_tag(cc, cf, sc->sc_bus, sc->sc_device, function);
id = cardbus_conf_read(cc, cf, tag, CARDBUS_ID_REG);
class = cardbus_conf_read(cc, cf, tag, CARDBUS_CLASS_REG);
cis_ptr = cardbus_conf_read(cc, cf, tag, CARDBUS_CIS_REG);
+ /* Invalid vendor ID value? */
+ if (CARDBUS_VENDOR(id) == 0xffff)
+ continue;
+
DPRINTF(("cardbus_attach_card: Vendor 0x%x, Product 0x%x, CIS 0x%x\n",
CARDBUS_VENDOR(id), CARDBUS_PRODUCT(id), cis_ptr));
-
- bzero(tuple, 2048);
-
- if (CARDBUS_CIS_ASI_TUPLE == (CARDBUS_CIS_ASI(cis_ptr))) {
- /* Tuple is in Cardbus config space */
- int i = cis_ptr & CARDBUS_CIS_ADDRMASK;
- int j = 0;
- for (; i < 0xff; i += 4) {
- u_int32_t e = (cf->cardbus_conf_read)(cc, tag, i);
- tuple[j] = 0xff & e;
- e >>= 8;
- tuple[j + 1] = 0xff & e;
- e >>= 8;
- tuple[j + 2] = 0xff & e;
- e >>= 8;
- tuple[j + 3] = 0xff & e;
- j += 4;
- }
- } else if (CARDBUS_CIS_ASI(cis_ptr) <= CARDBUS_CIS_ASI_BAR5) {
- /* int bar = CARDBUS_CIS_ASI_BAR(cis_ptr);*/
- }
-
-
- decode_tuples(tuple, 2048);
-
- {
- struct cardbus_attach_args ca;
-
+ /* we need to allocate the ct here, since we might
+ need it when reading the CIS */
if (NULL == (ct = (cardbus_devfunc_t)malloc(sizeof(struct cardbus_devfunc),
M_DEVBUF, M_NOWAIT))) {
panic("no room for cardbus_tag");
@@ -316,11 +465,22 @@
ca.ca_intrline = sc->sc_intrline;
+ bzero(tuple, 2048);
+
+ if(cardbus_read_tuples(&ca, cis_ptr, tuple, sizeof(tuple))) {
+ printf("cardbus_attach_card: failed to read CIS\n");
+ free(ct, M_DEVBUF);
+ continue;
+ }
+
+ decode_tuples(tuple, 2048);
+
+
if (NULL == (csc = config_found_sm((void *)sc, &ca, cardbusprint, cardbussubmatch))) {
/* do not match */
- cf->cardbus_power(cc, CARDBUS_VCC_0V);
- sc->sc_poweron_func = 0; /* no functions on */
- free(cc, M_DEVBUF);
+ disable_function(sc, function);
+ free(ct, M_DEVBUF);
+ *previous_next = NULL;
} else {
/* found */
previous_next = &(ct->ct_next);
@@ -328,7 +488,11 @@
++no_work_funcs;
}
}
+ /* if we didn't attach to any function, power down card */
+ disable_function(sc, 8); /* XXX see comment above */
+ if(no_work_funcs == 0)
+ free(cc, M_DEVBUF); /* should this really be freed here? */
return no_work_funcs;
}
--- cardbus_map.c 1999/10/15 06:42:21 1.2
+++ cardbus_map.c 1999/10/15 15:39:51
@@ -87,7 +87,8 @@
cardbusreg_t address, mask;
int s;
- if (reg < PCI_MAPREG_START || reg >= PCI_MAPREG_END || (reg & 3)) {
+ if (reg != CARDBUS_ROM_REG
+ && (reg < PCI_MAPREG_START || reg >= PCI_MAPREG_END || (reg & 3))) {
panic("cardbus_io_find: bad request");
}
--- cardbusvar.h 1999/10/15 06:42:22 1.2
+++ cardbusvar.h 1999/10/15 15:39:51
@@ -114,6 +114,7 @@
#define CARDBUS_BASE4_REG 0x20
#define CARDBUS_BASE5_REG 0x24
#define CARDBUS_CIS_REG 0x28
+#define CARDBUS_ROM_REG 0x30
# define CARDBUS_CIS_ASIMASK 0x07
# define CARDBUS_CIS_ASI(x) (CARDBUS_CIS_ASIMASK & (x))
# define CARDBUS_CIS_ASI_TUPLE 0x00
@@ -358,7 +359,7 @@
#define Cardbus_conf_read(ct, tag, offs) (*(ct)->ct_cf->cardbus_conf_read)((ct)->ct_cf, (tag), (offs))
#define cardbus_conf_read(cc, cf, tag, offs) ((cf)->cardbus_conf_read)((cc), (tag), (offs))
-#define Cardbus_conf_write(ct, tag, offs, val) (*(cc)->ct_cf->cardbus_conf_write)((ct)->ct_cf, (tag), (offs), (val))
+#define Cardbus_conf_write(ct, tag, offs, val) (*(ct)->ct_cf->cardbus_conf_write)((ct)->ct_cf, (tag), (offs), (val))
#define cardbus_conf_write(cc, cf, tag, offs, val) ((cf)->cardbus_conf_write)((cc), (tag), (offs), (val))
#endif /* SYS_DEV_CARDBUS_CARDBUSVAR_H */
>Audit-Trail:
>Unformatted: