From owner-freebsd-hackers@FreeBSD.ORG Mon Sep 13 06:03:50 2004 Return-Path: Delivered-To: freebsd-hackers@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id E83EC16A4CE for ; Mon, 13 Sep 2004 06:03:49 +0000 (GMT) Received: from harmony.village.org (rover.village.org [168.103.84.182]) by mx1.FreeBSD.org (Postfix) with ESMTP id 4318643D2F for ; Mon, 13 Sep 2004 06:03:49 +0000 (GMT) (envelope-from imp@bsdimp.com) Received: from localhost (warner@rover2.village.org [10.0.0.1]) by harmony.village.org (8.13.1/8.13.1) with ESMTP id i8D62PZE021784 for ; Mon, 13 Sep 2004 00:02:25 -0600 (MDT) (envelope-from imp@bsdimp.com) Date: Mon, 13 Sep 2004 00:03:02 -0600 (MDT) Message-Id: <20040913.000302.94315208.imp@bsdimp.com> To: hackers@freebsd.org From: "M. Warner Losh" In-Reply-To: <20040912.233946.30892794.imp@bsdimp.com> References: <20040912.233946.30892794.imp@bsdimp.com> X-Mailer: Mew version 3.3 on Emacs 21.3 / Mule 5.0 (SAKAKI) Mime-Version: 1.0 Content-Type: Multipart/Mixed; boundary="--Next_Part(Mon_Sep_13_00:03:02_2004_037)--" Content-Transfer-Encoding: 7bit Subject: Re: Preliminary fdc patches X-BeenThere: freebsd-hackers@freebsd.org X-Mailman-Version: 2.1.1 Precedence: list List-Id: Technical Discussions relating to FreeBSD List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 13 Sep 2004 06:03:50 -0000 ----Next_Part(Mon_Sep_13_00:03:02_2004_037)-- Content-Type: Text/Plain; charset=us-ascii Content-Transfer-Encoding: 7bit In message: <20040912.233946.30892794.imp@bsdimp.com> "M. Warner Losh" writes: : Can people test these? I seem to have only good, well behaved fdc : devices :-) These patches should be considered experimental. I've : tried them on one machine only. Hmmm. Last minute changes suck. The last patch will crash in some cease. This one should be a lot better. Warner ----Next_Part(Mon_Sep_13_00:03:02_2004_037)-- Content-Type: Text/Plain; charset=us-ascii Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename=fdc-diff Only in /dell/imp/FreeBSD/src/sys/dev/fdc: .#fdc.c.1.276 Only in /dell/imp/FreeBSD/src/sys/dev/fdc: CVS Only in .: fd.c diff -du /dell/imp/FreeBSD/src/sys/dev/fdc/fdc.c ./fdc.c --- /dell/imp/FreeBSD/src/sys/dev/fdc/fdc.c Mon Sep 13 00:01:47 2004 +++ ./fdc.c Sun Sep 12 23:59:09 2004 @@ -197,9 +197,18 @@ #define FDCTL 7 /* Control Register (W) */ /* - * this is the secret PIO data port (offset from base) + * The YE-DATA PC Card floppies use PIO to read in the data rather than + * DMA due to the wild variability of DMA for the PC Card devices. In + * addition, if we cannot setup the DMA resources for the ISA attachment, + * we'll use this same offset for data transfer. + * + * For this mode, offset 0 and 1 must be used to setup the transfer + * for this floppy. This means they are only available on those systems + * that map them to the floppy drive. Newer systems do not do this, and + * we should likely prohibit access to them (or disallow NODMA to be set). */ -#define FDC_YE_DATAPORT 6 +#define FDBCDR 0 /* And 1 */ +#define FD_YE_DATAPORT 6 /* Drive Data port */ #define FDI_DCHG 0x80 /* diskette has been changed */ /* requires drive and motor being selected */ @@ -337,6 +346,19 @@ return bus_space_read_1(fdc->ctlt, fdc->ctlh, fdc->ctl_off); } +/* + * Magic pseudo-DMA initialization for YE FDC. Sets count and + * direction. + */ +static void +fdbcdr_wr(struct fdc_data *fdc, int iswrite, uint16_t count) +{ + bus_space_write_1(fdc->portt, fdc->porth, fdc->port_off + FDBCDR, + (count - 1) & 0xff); + bus_space_write_1(fdc->portt, fdc->porth, fdc->port_off + FDBCDR + 1, + ((iswrite ? 0x80 : 0) | (((count - 1) >> 8) & 0x7f))); +} + static int fdc_err(struct fdc_data *fdc, const char *s) { @@ -634,18 +656,6 @@ } /* - * Magic pseudo-DMA initialization for YE FDC. Sets count and - * direction. - */ -#define SET_BCDR(fdc,wr,cnt,port) \ - do { \ - bus_space_write_1(fdc->portt, fdc->porth, fdc->port_off + port, \ - ((cnt)-1) & 0xff); \ - bus_space_write_1(fdc->portt, fdc->porth, fdc->port_off + port + 1, \ - ((wr ? 0x80 : 0) | ((((cnt)-1) >> 8) & 0x7f))); \ - } while (0) - -/* * fdc_pio(): perform programmed IO read/write for YE PCMCIA floppy. */ static void @@ -660,13 +670,13 @@ count = fdc->fd->fd_iosize; if (bp->bio_cmd == BIO_READ) { - SET_BCDR(fdc, 0, count, 0); + fdbcdr_wr(fdc, 0, count); bus_space_read_multi_1(fdc->portt, fdc->porth, fdc->port_off + - FDC_YE_DATAPORT, cptr, count); + FD_YE_DATAPORT, cptr, count); } else { bus_space_write_multi_1(fdc->portt, fdc->porth, fdc->port_off + - FDC_YE_DATAPORT, cptr, count); - SET_BCDR(fdc, 0, count, 0); + FD_YE_DATAPORT, cptr, count); + fdbcdr_wr(fdc, 0, count); /* needed? */ } } @@ -940,7 +950,7 @@ /* Do PIO if we have to */ if (fdc->flags & FDC_NODMA) { if (bp->bio_cmd & (BIO_READ|BIO_WRITE|BIO_FMT)) - SET_BCDR(fdc, 1, fd->fd_iosize, 0); + fdbcdr_wr(fdc, 1, fd->fd_iosize); if (bp->bio_cmd & (BIO_WRITE|BIO_FMT)) fdc_pio(fdc); } @@ -1484,39 +1494,30 @@ device_t dev; dev = fdc->fdc_dev; - if (fdc->fdc_intr) { + if (fdc->fdc_intr) BUS_TEARDOWN_INTR(device_get_parent(dev), dev, fdc->res_irq, fdc->fdc_intr); - fdc->fdc_intr = NULL; - } - if (fdc->res_irq != 0) { - bus_deactivate_resource(dev, SYS_RES_IRQ, fdc->rid_irq, - fdc->res_irq); + fdc->fdc_intr = NULL; + if (fdc->res_irq != NULL) bus_release_resource(dev, SYS_RES_IRQ, fdc->rid_irq, - fdc->res_irq); - fdc->res_irq = NULL; - } - if (fdc->res_ctl != 0) { - bus_deactivate_resource(dev, SYS_RES_IOPORT, fdc->rid_ctl, - fdc->res_ctl); + fdc->res_irq); + fdc->res_irq = NULL; + if (fdc->res_ctl != NULL) bus_release_resource(dev, SYS_RES_IOPORT, fdc->rid_ctl, - fdc->res_ctl); - fdc->res_ctl = NULL; - } - if (fdc->res_ioport != 0) { - bus_deactivate_resource(dev, SYS_RES_IOPORT, fdc->rid_ioport, - fdc->res_ioport); + fdc->res_ctl); + fdc->res_ctl = NULL; + if (fdc->res_sts != NULL) + bus_release_resource(dev, SYS_RES_IOPORT, fdc->rid_sts, + fdc->res_sts); + fdc->res_sts = NULL; + if (fdc->res_ioport != NULL) bus_release_resource(dev, SYS_RES_IOPORT, fdc->rid_ioport, - fdc->res_ioport); - fdc->res_ioport = NULL; - } - if (fdc->res_drq != 0) { - bus_deactivate_resource(dev, SYS_RES_DRQ, fdc->rid_drq, - fdc->res_drq); + fdc->res_ioport); + fdc->res_ioport = NULL; + if (fdc->res_drq != NULL) bus_release_resource(dev, SYS_RES_DRQ, fdc->rid_drq, - fdc->res_drq); - fdc->res_drq = NULL; - } + fdc->res_drq); + fdc->res_drq = NULL; } int diff -du /dell/imp/FreeBSD/src/sys/dev/fdc/fdc_isa.c ./fdc_isa.c --- /dell/imp/FreeBSD/src/sys/dev/fdc/fdc_isa.c Mon Sep 13 00:01:47 2004 +++ ./fdc_isa.c Sun Sep 12 23:59:09 2004 @@ -57,9 +57,8 @@ int fdc_isa_alloc_resources(device_t dev, struct fdc_data *fdc) { - int ispnp, nports; + int nports = 6; - ispnp = (fdc->flags & FDC_ISPNP) != 0; fdc->fdc_dev = dev; fdc->rid_ioport = 0; fdc->rid_irq = 0; @@ -69,99 +68,84 @@ /* * On standard ISA, we don't just use an 8 port range * (e.g. 0x3f0-0x3f7) since that covers an IDE control - * register at 0x3f6. + * register at 0x3f6. So, on older hardware, we use + * 0x3f0-0x3f5 and 0x3f7. However, some BIOSs omit the + * control port, while others start at 0x3f2. Of the latter, + * sometimes we have two resources, other times we have one. + * We have to deal with the following cases: * - * Isn't PC hardware wonderful. + * 1: 0x3f0-0x3f5 # very rare + * 2: 0x3f0 # hints -> 0x3f0-0x3f5,0x3f7 + * 3: 0x3f0-0x3f5,0x3f7 # Most common + * 4: 0x3f2-0x3f5,0x3f7 # Second most common + * 5: 0x3f2-0x3f5 # implies 0x3f7 too. + * 6: 0x3f2-0x3f3,0x3f4-0x3f5,0x3f7 # becoming common + * 7: 0x3f2-0x3f3,0x3f4-0x3f5 # rare + * + * The following code is generic for any value of 0x3fx :-) */ - nports = ispnp ? 1 : 6; /* - * Some ACPI BIOSen have _CRS objects for the floppy device that - * split the I/O port resource into several resources. We detect - * this case by checking if there are more than 2 IOPORT resources. - * If so, we use the resource with the smallest start address as - * the port RID and the largest start address as the control RID. + * First, allocated the main range of ports. In the best of + * worlds, this is 4 or 6 ports. In others, well, that's + * why this function is so complicated. */ - if (bus_get_resource_count(dev, SYS_RES_IOPORT, 2) != 0) { - u_long min_start, max_start, tmp; - int i; - - /* Find the min/max start addresses and their RIDs. */ - max_start = 0ul; - min_start = ~0ul; - for (i = 0; bus_get_resource_count(dev, SYS_RES_IOPORT, i) > 0; - i++) { - tmp = bus_get_resource_start(dev, SYS_RES_IOPORT, i); - KASSERT(tmp != 0, ("bogus resource")); - if (tmp < min_start) { - min_start = tmp; - fdc->rid_ioport = i; - } - if (tmp > max_start) { - max_start = tmp; - fdc->rid_ctl = i; - } - } - } - fdc->res_ioport = bus_alloc_resource(dev, SYS_RES_IOPORT, &fdc->rid_ioport, 0ul, ~0ul, nports, RF_ACTIVE); if (fdc->res_ioport == 0) { - device_printf(dev, "cannot reserve I/O port range (%d ports)\n", - nports); - return ENXIO; + device_printf(dev, "cannot allocate I/O port (%d ports)\n", + nports); + return (ENXIO); } fdc->portt = rman_get_bustag(fdc->res_ioport); fdc->porth = rman_get_bushandle(fdc->res_ioport); /* - * Some BIOSen report the device at 0x3f2-0x3f5,0x3f7 - * and some at 0x3f0-0x3f5,0x3f7. We detect the former - * by checking the size and adjust the port address - * accordingly. + * Handle cases 4-7 above */ - if (bus_get_resource_count(dev, SYS_RES_IOPORT, 0) == 4) - fdc->port_off = -2; + fdc->port_off = -(fdc->porth & 0x7); /* - * Register the control port range as rid 1 if it - * isn't there already. Most PnP BIOSen will have - * already done this but non-PnP configurations don't. - * - * And some (!!) report 0x3f2-0x3f5 and completely - * leave out the control register! It seems that some - * non-antique controller chips have a different - * method of programming the transfer speed which - * doesn't require the control register, but it's - * mighty bogus as the chip still responds to the - * address for the control register. + * Deal with case 6 and 7: FDSTS and FDSATA are in rid 1. */ - if (bus_get_resource_count(dev, SYS_RES_IOPORT, 1) == 0) { - u_long ctlstart; - /* Find the control port, usually 0x3f7 */ - ctlstart = rman_get_start(fdc->res_ioport) + fdc->port_off + 7; - bus_set_resource(dev, SYS_RES_IOPORT, 1, ctlstart, 1); + if (rman_get_size(fdc->res_ioport) == 2) { + fdc->rid_sts = 1; + fdc->res_sts = bus_alloc_resource_any(dev, SYS_RES_IOPORT, + &fdc->rid_sts, RF_ACTIVE); + if (fdc->res_sts == NULL) { + device_printf(dev, "Can't alloc rid 1"); + fdc_release_resources(fdc); + return (ENXIO); + } + fdc->rid_ctl++; + fdc->sts_off = -4; + } else { + fdc->res_sts = NULL; + fdc->sts_off = fdc->port_off; } + fdc->stst = rman_get_bustag(fdc->res_sts); + fdc->stsh = rman_get_bushandle(fdc->res_sts); /* - * Now (finally!) allocate the control port. + * allocate the control port. For cases 1, 2, 5 and 7, we + * fake it from the ioports resource. */ fdc->res_ctl = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &fdc->rid_ctl, RF_ACTIVE); - if (fdc->res_ctl == 0) { - device_printf(dev, - "cannot reserve control I/O port range (control port)\n"); - return ENXIO; + if (fdc->res_ctl == NULL) { + fdc->ctl_off = 7 + fdc->port_off; + fdc->res_ctl = NULL; + } else { + fdc->ctl_off = 0; } fdc->ctlt = rman_get_bustag(fdc->res_ctl); fdc->ctlh = rman_get_bushandle(fdc->res_ctl); - fdc->ctl_off = 0; fdc->res_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &fdc->rid_irq, - RF_ACTIVE | RF_SHAREABLE); + RF_ACTIVE | RF_SHAREABLE); if (fdc->res_irq == 0) { device_printf(dev, "cannot reserve interrupt line\n"); - return ENXIO; + return (ENXIO); } if ((fdc->flags & FDC_NODMA) == 0) { @@ -169,12 +153,13 @@ &fdc->rid_drq, RF_ACTIVE | RF_SHAREABLE); if (fdc->res_drq == 0) { device_printf(dev, "cannot reserve DMA request line\n"); + /* This is broken and doesn't work for ISA case */ fdc->flags |= FDC_NODMA; } else fdc->dmachan = rman_get_start(fdc->res_drq); } - return 0; + return (0); } static int diff -du /dell/imp/FreeBSD/src/sys/dev/fdc/fdc_pccard.c ./fdc_pccard.c --- /dell/imp/FreeBSD/src/sys/dev/fdc/fdc_pccard.c Mon Sep 13 00:01:47 2004 +++ ./fdc_pccard.c Sun Sep 12 23:53:01 2004 @@ -65,6 +65,9 @@ } fdc->portt = rman_get_bustag(fdc->res_ioport); fdc->porth = rman_get_bushandle(fdc->res_ioport); + fdc->stst = fdc->portt; + fdc->stsh = fdc->porth; + fdc->sts_off = 0; fdc->ctlt = fdc->portt; fdc->ctlh = fdc->porth; fdc->ctl_off = 7; diff -du /dell/imp/FreeBSD/src/sys/dev/fdc/fdcvar.h ./fdcvar.h --- /dell/imp/FreeBSD/src/sys/dev/fdc/fdcvar.h Mon Sep 13 00:01:47 2004 +++ ./fdcvar.h Sun Sep 12 23:59:09 2004 @@ -57,14 +57,17 @@ int fdc_errs; /* number of logged errors */ struct bio_queue_head head; struct bio *bp; /* active buffer */ - struct resource *res_ioport, *res_ctl, *res_irq, *res_drq; - int rid_ioport, rid_ctl, rid_irq, rid_drq; - int port_off; + struct resource *res_ioport, *res_sts, *res_ctl, *res_irq, *res_drq; + int rid_ioport, rid_sts, rid_ctl, rid_irq, rid_drq; bus_space_tag_t portt; bus_space_handle_t porth; + bus_space_tag_t stst; + bus_space_handle_t stsh; bus_space_tag_t ctlt; bus_space_handle_t ctlh; + int port_off; int ctl_off; + int sts_off; void *fdc_intr; struct device *fdc_dev; struct mtx fdc_mtx; ----Next_Part(Mon_Sep_13_00:03:02_2004_037)----