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: