Modem + Network in Xircom cards, and maybe others

From: Carlos Velasco <freebsd_at_newipnet.com>
Date: Sun, 02 May 2004 12:59:23 +0200
Xircom cards with multiple functions are not MFC compliant, that makes them
to fail in CURRENT and only one function works (last one in the CIS,
Network).

I have patched pccard to provide support for both functions. I have
followed this behaviour:

/* We have a non-MFC compliant card, it puts more
 * than 1 FUNCID in the CIS without LONGLINK.
 * a) We put the functions in the list ala MFC.
 * b) Copy last CFG entry for previous function,
 *    not sure if this is right, but usually works.
 */

Also I have needed to tweak if_xe_pccard because it was claiming itself as
the right driver when the function was serial and also another tweak to
proper handling of matches.

Patch works, however I'm seeing buffer overflows in sio when I issue a
"ATI11" command with minicom (WinXP works fine wth this):
sio4: 118 more interrupt-level buffer overflows (total 118)
sio4: 162 more interrupt-level buffer overflows (total 280)

In my laptop, cbb is taking irq11:
sio4: <Xircom CreditCard Ethernet 10/100 + Modem 56> at port 0x2e8-0x2ef
irq 11 function 0 config 39 on pccard0
sio4: type 16550A
sio4: unable to activate interrupt in fast mode - using normal mode
...
xe0: <Xircom CreditCard Ethernet 10/100 + Modem 56> at port 0x100-0x107 irq
11 function 1 config 63 on pccard0
xe0: [GIANT-LOCKED]
xe0: Xircom CreditCard Ethernet 10/100 + Modem 56, version 0x55/0x05,
100Mbps capable, with modem
xe0: Ethernet address: 00:10:a4:f6:2f:73

Issuing vmstat -i, I don't think irq11 is handling too many interrupts:
interrupt                          total       rate
irq0: clk                           9735         98
irq1: atkbd0                         410          4
irq3: sio1                            24          0
irq4: sio0                             2          0
irq5: pcm0                             1          0
irq6: fdc0                             2          0
irq7: ppc0                             1          0
irq8: rtc                          12461        125
irq9: acpi0                            1          0
irq11: cbb0 cbb1+                    167          1
irq13: npx0                            1          0
irq14: ata0                         2863         28
irq15: ata1                           58          0
Total                              25726        259

Also, I thought that it could be the network function to be the cause of
overflow problem, so I hacked the code to leave only the sio alone, it
didn't show any difference.
I would need some help with this problem.

Warner, I still needed to patch pccard to force 64k alignment for my TI1225
for this to work as my laptop hangs-up if i don't do it.


Here's the patch, so long...

diff -ru sys/dev/pccard/pccard.c sysnew/dev/pccard/pccard.c
--- sys/dev/pccard/pccard.c	Wed Mar 17 17:50:38 2004
+++ sysnew/dev/pccard/pccard.c	Sat May  1 09:47:57 2004
_at__at_ -955,8 +955,8 _at__at_
 	struct pccard_softc *sc = PCCARD_SOFTC(bus);
 
 	device_printf(bus, "<unknown card>");
-	printf(" (manufacturer=0x%04x, product=0x%04x) at function %d\n",
-	  sc->card.manufacturer, sc->card.product, func->number);
+	printf(" (manufacturer=0x%04x, product=0x%04x, prodext=0x%02x) at
function %d\n",
+	  sc->card.manufacturer, sc->card.product, sc->card.prodext,
func->number);
 	device_printf(bus, "   CIS info: %s, %s, %s\n", sc->card.cis1_info[0],
 	  sc->card.cis1_info[1], sc->card.cis1_info[2]);
 	return;
_at__at_ -1075,6 +1075,7 _at__at_
 	int passthrough = (device_get_parent(child) != dev);
 	int isdefault = (start == 0 && end == ~0UL && count == 1);
 	struct resource *r = NULL;
+       u_int align;
 
 	/* XXX I'm no longer sure this is right */
 	if (passthrough) {
_at__at_ -1090,8 +1091,15 _at__at_
 	if (rle == NULL || rle->res == NULL) {
 		/* Do we want this device to own it? */
 		/* XXX I think so, but that might be lame XXX */
+
+               /* force 64k page align */
+               if (type == SYS_RES_MEMORY)
+                   align = (flags & ~RF_ALIGNMENT_MASK) |
+                       rman_make_alignment_flags(64*1024);
+               else
+                   align = flags;
 		r = bus_alloc_resource(dev, type, rid, start, end,
-		  count, flags /* XXX aligment? */);
+                 count, align);
 		if (r == NULL)
 		    goto bad;
 		resource_list_add(&dinfo->resources, type, *rid,
diff -ru sys/dev/pccard/pccard_cis.c sysnew/dev/pccard/pccard_cis.c
--- sys/dev/pccard/pccard_cis.c	Mon Apr 12 20:56:34 2004
+++ sysnew/dev/pccard/pccard_cis.c	Sat May  1 09:47:57 2004
_at__at_ -96,6 +96,8 _at__at_
 
 	state.pf = NULL;
 
+	state.card->mfc = 0;
+
 	tsleep(&state, 0, "pccard", hz);
 	if (pccard_scan_cis(sc->dev, pccard_parse_cis_tuple,
 	    &state) == -1)
_at__at_ -663,6 +665,7 _at__at_
 		 * up.
 		 */
 		state->gotmfc = 1;
+		state->card->mfc = 1;
 		break;
 #ifdef PCCARDCISDEBUG
 	case CISTPL_DEVICE:
_at__at_ -803,6 +806,42 _at__at_
 
 			STAILQ_INSERT_TAIL(&state->card->pf_head, state->pf,
 			    pf_list);
+		} else if (state->pf->function != PCCARD_FUNCTION_UNSPEC) {
+			/* We have a non-MFC compliant card, it puts more
+			 * than 1 FUNCID in the CIS without LONGLINK.
+			 * a) We put the functions in the list ala MFC.
+			 * b) Copy last CFG entry for previous function,
+			 *    not sure if this is right, but usually works.
+			 */
+			struct pccard_config_entry *cfe, *qcfe;
+			uint32_t	ccr_base = state->pf->ccr_base;
+			uint32_t	ccr_mask = state->pf->ccr_mask;
+
+			cfe = NULL;
+			STAILQ_FOREACH(qcfe, &state->pf->cfe_head, cfe_list) {
+				if (qcfe->number == state->pf->last_config_index) {
+				cfe = (struct pccard_config_entry *)
+				    malloc(sizeof(*cfe), M_DEVBUF, M_NOWAIT);
+				*cfe = *qcfe;
+				break;
+				}
+			}
+
+			state->pf = malloc(sizeof(*state->pf), M_DEVBUF,
+			    M_NOWAIT | M_ZERO);
+			state->pf->number = state->count++;
+			state->pf->last_config_index = cfe->number;
+			state->pf->ccr_base = ccr_base;
+			state->pf->ccr_mask = ccr_mask;
+
+			STAILQ_INIT(&state->pf->cfe_head);
+			if (cfe) 
+				STAILQ_INSERT_TAIL(&state->pf->cfe_head,
+				    cfe, cfe_list);
+
+			STAILQ_INSERT_TAIL(&state->card->pf_head, state->pf,
+			    pf_list);
+		
 		}
 		state->pf->function = pccard_tuple_read_1(tuple, 0);
 
diff -ru sys/dev/pccard/pccardvar.h sysnew/dev/pccard/pccardvar.h
--- sys/dev/pccard/pccardvar.h	Sun Nov  2 20:18:19 2003
+++ sysnew/dev/pccard/pccardvar.h	Sat May  1 09:47:57 2004
_at__at_ -179,6 +179,7 _at__at_
 	int32_t		product;
 #define	PCMCIA_PRODUCT_INVALID		-1
 	int16_t		prodext;
+	int		mfc;
 	uint16_t	error;
 #define	PCMCIA_CIS_INVALID		{ NULL, NULL, NULL, NULL }
 	STAILQ_HEAD(, pccard_function) pf_head;
_at__at_ -284,8 +285,9 _at__at_
 #define	PCCARD_SPACE_IO		2
 
 #define	pccard_mfc(sc)							\
-		(STAILQ_FIRST(&(sc)->card.pf_head) &&			\
-		 STAILQ_NEXT(STAILQ_FIRST(&(sc)->card.pf_head),pf_list))
+		(sc->card.mfc)
+/*		(STAILQ_FIRST(&(sc)->card.pf_head) &&			\
+		 STAILQ_NEXT(STAILQ_FIRST(&(sc)->card.pf_head),pf_list)) */
 
 #define	pccard_io_alloc(pf, start, size, align, pciop)			\
 	(pccard_chip_io_alloc((pf)->sc->pct, pf->sc->pch, (start),	\
diff -ru sys/dev/xe/if_xe_pccard.c sysnew/dev/xe/if_xe_pccard.c
--- sys/dev/xe/if_xe_pccard.c	Sun Apr 11 16:34:29 2004
+++ sysnew/dev/xe/if_xe_pccard.c	Sat May  1 09:48:24 2004
_at__at_ -402,6 +402,7 _at__at_
 	const struct xe_pccard_product* xpp;
 	u_int16_t prodext;
 
+
 	DEVPRINTF(2, (dev, "pccard_product_match\n"));
 
 	xpp = (const struct xe_pccard_product*)ent;
_at__at_ -409,6 +410,8 _at__at_
 
 	if (xpp->prodext != prodext)
 		vpfmatch = 0;
+	else
+		vpfmatch++;
 
 	return (vpfmatch);
 }
_at__at_ -416,8 +419,19 _at__at_
 static int
 xe_pccard_match(device_t dev)
 {
+	int		error = 0;
+	u_int32_t	fcn = PCCARD_FUNCTION_UNSPEC;
 	const struct pccard_product *pp;
 
+	error = pccard_get_function(dev, &fcn);
+	if (error != 0)
+		return (error);
+	/*
+	 * If not a network card, we are not the right driver.
+	 */
+	if (fcn != PCCARD_FUNCTION_NETWORK)
+		return (ENXIO);
+
 	DEVPRINTF(2, (dev, "pccard_match\n"));
 
 	pp = (const struct pccard_product*)xe_pccard_products;
_at__at_ -425,7 +439,6 _at__at_
 	if ((pp = pccard_product_lookup(dev, pp,
 	     sizeof(xe_pccard_products[0]), xe_pccard_product_match)) != NULL)
 		return (0);
-
 	return (EIO);
 }
 


Regards,
Carlos Velasco
Received on Sun May 02 2004 - 02:01:31 UTC

This archive was generated by hypermail 2.4.0 : Wed May 19 2021 - 11:37:52 UTC