Date: Thu, 10 Aug 2000 18:40:56 +0400 (MSD) From: vak@cronyx.ru To: FreeBSD-gnats-submit@freebsd.org Subject: kern/20523: [patch] -current, sio driver, support for PCI multiport cards Message-ID: <200008101440.SAA00350@crox.cronyx.ru>
next in thread | raw e-mail | index | archive | help
>Number: 20523
>Category: kern
>Synopsis: Support for PCI multiport cards for sio driver
>Confidential: no
>Severity: serious
>Priority: medium
>Responsible: freebsd-bugs
>State: open
>Quarter:
>Keywords:
>Date-Required:
>Class: change-request
>Submitter-Id: current-users
>Arrival-Date: Thu Aug 10 08:00:01 PDT 2000
>Closed-Date:
>Last-Modified:
>Originator: Serge Vakulenko
>Release: FreeBSD-current i386
>Organization:
Cronyx Engineering Ltd.
>Environment:
FreeBSD-current, Cronyx-Omega-PCI serial multiport adapters.
>Description:
1) Split the sioattach() routine. Leave the isa-dependent
part in sioattach(), and build the bus-independent
attachment function sio_attach_unit().
2) Change the com_addr macro. Use the array of pointers,
not the devclass_get_softc routine, which is inadequate
for multiport adapters.
3) Change sio_pci_attach, handle multiport adapters.
For a new adapter type, add a string to pci_ids[].
The adapters are parameterized by a number of ports,
fifo size, hardware rts/cts support and i/o address step.
Pci ports get unit numbers, starting from the last
isa unit number. No sio_pci_kludge_unit() is needed.
The option COM_MULTIPORT is not needed for pci multiport adapters.
4) Add sio_pci_intr() routine for handling interrupts
from PCI multiport adapters.
Tested on Cronyx Omega-PCI 8-channel adapter.
>How-To-Repeat:
>Fix:
--- sio-current.c Wed Jul 5 02:17:45 2000
+++ sio.c Thu Aug 10 18:17:55 2000
@@ -288,17 +288,31 @@
u_char obuf2[256];
};
+#define MAXCHAN 8 /* up to 8 channels per multiport */
+
+struct multicom {
+ int nchan; /* channels per adapter */
+ struct resource *res;
+ struct resource *irq;
+ void *intrhand;
+ struct com_s com [MAXCHAN];
+};
+
#ifdef COM_ESP
static int espattach __P((struct com_s *com, Port_t esp_port));
#endif
static int sioattach __P((device_t dev, int rid));
static int sio_isa_attach __P((device_t dev));
+static int sio_attach_unit __P((struct com_s *com, int unit, Port_t iobase,
+ u_int flags, bool_t no_irq,
+ bus_space_tag_t t, bus_space_handle_t h));
static timeout_t siobusycheck;
static timeout_t siodtrwakeup;
static void comhardclose __P((struct com_s *com));
static void sioinput __P((struct com_s *com));
static void siointr1 __P((struct com_s *com));
+static void sio_pci_intr __P((void *arg));
static void siointr __P((void *arg));
static int commctl __P((struct com_s *com, int bits, int how));
static int comparam __P((struct tty *tp, struct termios *t));
@@ -321,7 +335,6 @@
#if NPCI > 0
static int sio_pci_attach __P((device_t dev));
-static void sio_pci_kludge_unit __P((device_t dev));
static int sio_pci_probe __P((device_t dev));
#endif /* NPCI > 0 */
@@ -329,8 +342,9 @@
/* table and macro for fast conversion from a unit number to its com struct */
static devclass_t sio_devclass;
-#define com_addr(unit) ((struct com_s *) \
- devclass_get_softc(sio_devclass, unit))
+#define SIO_MAXUNITS 64 /* up to 64 ports */
+#define com_addr(unit) (p_com_addr[unit])
+static struct com_s *p_com_addr[SIO_MAXUNITS];
static device_method_t sio_isa_methods[] = {
/* Device interface */
@@ -373,9 +387,9 @@
};
static driver_t sio_pci_driver = {
- driver_name,
+ "siopci",
sio_pci_methods,
- sizeof(struct com_s),
+ sizeof(struct multicom),
};
#endif /* NPCI > 0 */
@@ -419,6 +433,7 @@
static struct callout_handle sio_timeout_handle
= CALLOUT_HANDLE_INITIALIZER(&sio_timeout_handle);
static int sio_numunits;
+static int sio_pci_numunits = NSIO;
static struct speedtab comspeedtab[] = {
{ 0, 0 },
@@ -576,12 +591,17 @@
struct pci_ids {
u_int32_t type;
const char *desc;
- int rid;
+ int rid; /* pci base address register */
+ int nchan; /* channels per adapter */
+ int iostep; /* addresses per channel */
+ int fifo_size; /* fifo size in bytes */
+ int hw_rts_cts; /* hardware rts/cts support */
};
static struct pci_ids pci_ids[] = {
{ 0x100812b9, "3COM PCI FaxModem", 0x10 },
{ 0x048011c1, "ActionTec 56k FAX PCI Modem", 0x14 },
+ { 0xc00110b5, "Cronyx Omega-PCI Serial Adapter", 0x18, 8, 8, 64, 1 },
{ 0x00000000, NULL, 0 }
};
@@ -591,6 +611,12 @@
{
u_int32_t type;
struct pci_ids *id;
+ struct multicom *d = device_get_softc(dev);
+ struct com_s *com;
+ Port_t iobase;
+ bus_space_tag_t bst;
+ bus_space_handle_t bsh, bsh_port;
+ int rid, offset, s, err = 0;
type = pci_get_devid(dev);
id = pci_ids;
@@ -598,37 +624,75 @@
id++;
if (id->desc == NULL)
return (ENXIO);
- sio_pci_kludge_unit(dev);
- return (sioattach(dev, id->rid));
-}
-/*
- * Don't cut and paste this to other drivers. It is a horrible kludge
- * which will fail to work and also be unnecessary in future versions.
- */
-static void
-sio_pci_kludge_unit(dev)
- device_t dev;
-{
- devclass_t dc;
- int err;
- int start;
- int unit;
+ bzero((char*)d, sizeof(*d));
+ s = splimp();
+ d->nchan = id->nchan > 1 ? id->nchan : 1;
+
+ /* Allocate i/o region. */
+ rid = id->rid;
+ d->res = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0, 1,
+ RF_ACTIVE);
+ if (! d->res) {
+ printf("sio%d: couldn't map ports/memory\n", sio_pci_numunits);
+ err = ENXIO;
+ goto fail;
+ }
- unit = 0;
- start = 0;
- while (resource_int_value("sio", unit, "port", &start) == 0 &&
- start > 0)
- unit++;
- if (device_get_unit(dev) < unit) {
- dc = device_get_devclass(dev);
- while (devclass_get_device(dc, unit))
- unit++;
- device_printf(dev, "moving to sio%d\n", unit);
- err = device_set_unit(dev, unit); /* EVIL DO NOT COPY */
- if (err)
- device_printf(dev, "error moving device %d\n", err);
+ /* Allocate interrupt. */
+ rid = 0;
+ d->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1,
+ RF_SHAREABLE | RF_ACTIVE);
+ if (! d->irq) {
+ printf("sio%d: couldn't map interrupt\n", sio_pci_numunits);
+ err = ENXIO;
+ goto fail;
+ }
+
+ /* Register the interrupt handler. */
+ err = bus_setup_intr(dev, d->irq, INTR_TYPE_TTY | INTR_TYPE_FAST,
+ sio_pci_intr, d, &d->intrhand);
+ if (err) {
+ printf("sio%d: couldn't set up irq\n", sio_pci_numunits);
+fail: if (d->res)
+ bus_release_resource(dev, SYS_RES_IOPORT,
+ id->rid, d->res);
+ if (d->irq)
+ bus_release_resource(dev, SYS_RES_IRQ, 0, d->irq);
+ goto done;
+ }
+
+ /* Attach sio ports. */
+ bst = rman_get_bustag(d->res);
+ bsh = rman_get_bushandle(d->res);
+ iobase = rman_get_start(d->res);
+ offset = 0;
+ for (com=d->com; com<d->com+d->nchan; ++com, offset+=id->iostep) {
+ /* Get a handle for a subregion of an already-mapped
+ * area of bus space. */
+#if waiting_for_somebody_to_implement_bus_space_subregion
+ if (bus_space_subregion (bst, bsh, offset, 8, &bsh_port) != 0) {
+ printf("sio%d: cannot get bus subregion\n",
+ sio_pci_numunits);
+ continue;
}
+#else
+ bsh_port = bsh + offset;
+#endif
+ /* Interrupt enable, do it _before_ sio_attach_unit. */
+ outb (iobase + offset + com_mcr,
+ d->nchan > 1 ? MCR_IENABLE : 0);
+
+ if (sio_attach_unit(com, sio_pci_numunits++, iobase + offset,
+ id->fifo_size << 24, 0, bst, bsh_port) != 0)
+ printf("sio%d: cannot attach\n", sio_pci_numunits);
+
+ /* Must do this _after_ sio_attach_unit. */
+ com->st16650a = id->hw_rts_cts;
+ }
+done:
+ splx (s);
+ return err;
}
static int
@@ -645,7 +709,7 @@
if (id->desc == NULL)
return (ENXIO);
device_set_desc(dev, id->desc);
- return (sioprobe(dev, id->rid));
+ return (0);
}
#endif /* NPCI > 0 */
@@ -1096,15 +1160,13 @@
int xrid;
{
struct com_s *com;
-#ifdef COM_ESP
- Port_t *espp;
-#endif
Port_t iobase;
int unit;
u_int flags;
int rid;
struct resource *port;
int ret;
+ int no_irq;
rid = xrid;
port = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
@@ -1117,6 +1179,66 @@
com = device_get_softc(dev);
flags = device_get_flags(dev);
+#ifdef COM_MULTIPORT
+ if (COM_ISMULTIPORT(flags)) {
+ device_t masterdev;
+
+ masterdev = devclass_get_device(sio_devclass,
+ COM_MPMASTER(flags));
+ no_irq = (masterdev == NULL || bus_get_resource(masterdev,
+ SYS_RES_IRQ, 0, NULL, NULL) != 0);
+ } else
+#endif /* COM_MULTIPORT */
+ no_irq = bus_get_resource(dev, SYS_RES_IRQ, 0, NULL, NULL) != 0;
+
+ ret = sio_attach_unit(com, unit, iobase, flags, no_irq,
+ rman_get_bustag(port), rman_get_bushandle(port));
+
+ if (ret != 0) {
+ /* Leave i/o resources allocated if this is a `cn'-level
+ * console, so that other devices can't snarf them. */
+ if (iobase != siocniobase)
+ bus_release_resource(dev, SYS_RES_IOPORT, rid, port);
+ return ret;
+ }
+
+ rid = 0;
+ com->irqres = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0ul, ~0ul, 1,
+ RF_ACTIVE);
+ if (com->irqres) {
+ ret = BUS_SETUP_INTR(device_get_parent(dev), dev, com->irqres,
+ INTR_TYPE_TTY | INTR_TYPE_FAST,
+ siointr, com, &com->cookie);
+ if (ret) {
+ ret = BUS_SETUP_INTR(device_get_parent(dev), dev,
+ com->irqres, INTR_TYPE_TTY,
+ siointr, com, &com->cookie);
+ if (ret == 0)
+ device_printf(dev, "unable to activate interrupt in fast mode - using normal mode");
+ }
+ if (ret)
+ device_printf(dev, "could not activate interrupt\n");
+ }
+ com->ioportres = port;
+ return 0;
+}
+
+int
+sio_attach_unit(com, unit, iobase, flags, no_irq, bst, bsh)
+ struct com_s *com;
+ int unit;
+ Port_t iobase;
+ u_int flags;
+ bool_t no_irq;
+ bus_space_tag_t bst;
+ bus_space_handle_t bsh;
+{
+#ifdef COM_ESP
+ Port_t *espp;
+#endif
+
+ if (unit >= SIO_MAXUNITS)
+ return ENXIO;
if (unit >= sio_numunits)
sio_numunits = unit + 1;
/*
@@ -1133,13 +1255,12 @@
*/
bzero(com, sizeof *com);
com->unit = unit;
- com->ioportres = port;
- com->bst = rman_get_bustag(port);
- com->bsh = rman_get_bushandle(port);
+ com->bst = bst;
+ com->bsh = bsh;
com->cfcr_image = CFCR_8BITS;
com->dtr_wait = 3 * hz;
com->loses_outints = COM_LOSESOUTINTS(flags) != 0;
- com->no_irq = bus_get_resource(dev, SYS_RES_IRQ, 0, NULL, NULL) != 0;
+ com->no_irq = no_irq;
com->tx_fifo_size = 1;
com->obufs[0].l_head = com->obuf1;
com->obufs[1].l_head = com->obuf2;
@@ -1175,12 +1296,6 @@
com->it_in.c_ispeed = com->it_in.c_ospeed = TTYDEF_SPEED;
if (siosetwater(com, com->it_in.c_ispeed) != 0) {
enable_intr();
- /*
- * Leave i/o resources allocated if this is a `cn'-level
- * console, so that other devices can't snarf them.
- */
- if (iobase != siocniobase)
- bus_release_resource(dev, SYS_RES_IOPORT, rid, port);
return (ENOMEM);
}
enable_intr();
@@ -1287,17 +1402,11 @@
#ifdef COM_MULTIPORT
if (COM_ISMULTIPORT(flags)) {
- device_t masterdev;
-
com->multiport = TRUE;
printf(" (multiport");
if (unit == COM_MPMASTER(flags))
printf(" master");
printf(")");
- masterdev = devclass_get_device(sio_devclass,
- COM_MPMASTER(flags));
- com->no_irq = (masterdev == NULL || bus_get_resource(masterdev,
- SYS_RES_IRQ, 0, NULL, NULL) != 0);
}
#endif /* COM_MULTIPORT */
if (unit == comconsole)
@@ -1306,6 +1415,8 @@
printf(" with a bogus IIR_TXRDY register");
printf("\n");
+ com_addr(unit) = com;
+
if (!sio_registered) {
register_swi(SWI_TTY, siopoll);
sio_registered = TRUE;
@@ -1326,24 +1437,6 @@
com->pps.ppscap = PPS_CAPTUREASSERT | PPS_CAPTURECLEAR;
pps_init(&com->pps);
- rid = 0;
- com->irqres = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0ul, ~0ul, 1,
- RF_ACTIVE);
- if (com->irqres) {
- ret = BUS_SETUP_INTR(device_get_parent(dev), dev, com->irqres,
- INTR_TYPE_TTY | INTR_TYPE_FAST,
- siointr, com, &com->cookie);
- if (ret) {
- ret = BUS_SETUP_INTR(device_get_parent(dev), dev,
- com->irqres, INTR_TYPE_TTY,
- siointr, com, &com->cookie);
- if (ret == 0)
- device_printf(dev, "unable to activate interrupt in fast mode - using normal mode");
- }
- if (ret)
- device_printf(dev, "could not activate interrupt\n");
- }
-
return (0);
}
@@ -1830,6 +1923,27 @@
} while (possibly_more_intrs);
COM_UNLOCK();
#endif /* COM_MULTIPORT */
+}
+
+static void
+sio_pci_intr(arg)
+ void *arg;
+{
+ struct multicom *d = arg;
+ struct com_s *com;
+ bool_t possibly_more_intrs;
+
+ disable_intr();
+ do {
+ possibly_more_intrs = FALSE;
+ for (com=d->com; com<d->com+d->nchan; ++com) {
+ if ((inb(com->int_id_port) & IIR_IMASK) != IIR_NOPEND) {
+ siointr1(com);
+ possibly_more_intrs = TRUE;
+ }
+ }
+ } while (possibly_more_intrs);
+ enable_intr();
}
static void
>Release-Note:
>Audit-Trail:
>Unformatted:
To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-bugs" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200008101440.SAA00350>
