diff options
author | Warner Losh <imp@FreeBSD.org> | 2005-01-19 07:46:38 +0000 |
---|---|---|
committer | Warner Losh <imp@FreeBSD.org> | 2005-01-19 07:46:38 +0000 |
commit | 973bfe6c4a9241699e6e256cfa8fd74532adfe97 (patch) | |
tree | 2b913234aa2be66ec2ed3171f91718934b9ebcff /sys/dev/fdc | |
parent | 33481e9d67da5a3ade37c2f6dbe1dfde3d3d6671 (diff) | |
download | src-973bfe6c4a9241699e6e256cfa8fd74532adfe97.tar.gz src-973bfe6c4a9241699e6e256cfa8fd74532adfe97.zip |
MFp4: overhaul of resource allocation
Rather than have a twisty maze of special case allocations, move
instead to a data driven allocation. This should be the most robust
way to cope with the resource problems that the multiplicity of ways
of encoding 5 registers that have the misfortune of not being a power
of 2 nor contiguous.
Also, make it less impossible that pccard will work. I've not been able
to get my libretto floppy working, but it now fails later than before.
phk and I had similar ideas on this during the 5.3 release cycle, but
it wasn't until recently that I could test more than one allocation
scenario.
MFC After: 1 month (5.4 if possible, 5.5 if not)
Notes
Notes:
svn path=/head/; revision=140469
Diffstat (limited to 'sys/dev/fdc')
-rw-r--r-- | sys/dev/fdc/fdc.c | 89 | ||||
-rw-r--r-- | sys/dev/fdc/fdc_isa.c | 149 | ||||
-rw-r--r-- | sys/dev/fdc/fdc_pccard.c | 30 | ||||
-rw-r--r-- | sys/dev/fdc/fdcvar.h | 24 |
4 files changed, 134 insertions, 158 deletions
diff --git a/sys/dev/fdc/fdc.c b/sys/dev/fdc/fdc.c index 7c515904c223..22124cb7d1e5 100644 --- a/sys/dev/fdc/fdc.c +++ b/sys/dev/fdc/fdc.c @@ -110,7 +110,6 @@ __FBSDID("$FreeBSD$"); * * 2.88M format has 2 x 36 x 512, allow for hacked up density. */ - #define MAX_BYTES_PER_CYL (2 * 40 * 512) /* @@ -196,15 +195,22 @@ static struct fd_type *fd_native_types[] = { #define FDCTL 7 /* Control Register (W) */ /* - * 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. + * 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. DMA was deleted from the PC Card specification in version + * 7.2 of the standard, but that post-dates the YE-DATA devices by many + * years. + * + * In addition, if we cannot setup the DMA resources for the ISA + * attachment, we'll use this same offset for data transfer. However, + * that almost certainly won't work. * * 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). + * for this floppy. This is OK for PC Card YE Data devices, but for + * ISA this is likely wrong. These registers 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 FDBCDR 0 /* And 1 */ #define FD_YE_DATAPORT 6 /* Drive Data port */ @@ -303,46 +309,60 @@ fdsettype(struct fd_data *fd, struct fd_type *ft) /* * Bus space handling (access to low-level IO). */ +__inline static void +fdregwr(struct fdc_data *fdc, int reg, uint8_t v) +{ + + bus_space_write_1(fdc->iot, fdc->ioh[reg], fdc->ioff[reg], v); +} + +__inline static uint8_t +fdregrd(struct fdc_data *fdc, int reg) +{ + + return bus_space_read_1(fdc->iot, fdc->ioh[reg], fdc->ioff[reg]); +} + static void fdctl_wr(struct fdc_data *fdc, u_int8_t v) { - bus_space_write_1(fdc->ctlt, fdc->ctlh, fdc->ctl_off, v); + fdregwr(fdc, FDCTL, v); } static void fdout_wr(struct fdc_data *fdc, u_int8_t v) { - bus_space_write_1(fdc->portt, fdc->porth, FDOUT+fdc->port_off, v); + fdregwr(fdc, FDOUT, v); } static u_int8_t fdsts_rd(struct fdc_data *fdc) { - return bus_space_read_1(fdc->portt, fdc->porth, FDSTS+fdc->port_off); + return fdregrd(fdc, FDSTS); } static void fddata_wr(struct fdc_data *fdc, u_int8_t v) { - bus_space_write_1(fdc->portt, fdc->porth, FDDATA+fdc->port_off, v); + fdregwr(fdc, FDDATA, v); } static u_int8_t fddata_rd(struct fdc_data *fdc) { - return bus_space_read_1(fdc->portt, fdc->porth, FDDATA+fdc->port_off); + return fdregrd(fdc, FDDATA); } static u_int8_t fdin_rd(struct fdc_data *fdc) { - return bus_space_read_1(fdc->ctlt, fdc->ctlh, fdc->ctl_off); + return fdregrd(fdc, FDCTL); } /* @@ -352,10 +372,9 @@ fdin_rd(struct fdc_data *fdc) 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))); + fdregwr(fdc, FDBCDR, (count - 1) & 0xff); + fdregwr(fdc, FDBCDR + 1, + (iswrite ? 0x80 : 0) | (((count - 1) >> 8) & 0x7f)); } static int @@ -669,11 +688,11 @@ fdc_pio(struct fdc_data *fdc) if (bp->bio_cmd == BIO_READ) { fdbcdr_wr(fdc, 0, count); - bus_space_read_multi_1(fdc->portt, fdc->porth, fdc->port_off + - FD_YE_DATAPORT, cptr, count); + bus_space_read_multi_1(fdc->iot, fdc->ioh[FD_YE_DATAPORT], + fdc->ioff[FD_YE_DATAPORT], cptr, count); } else { - bus_space_write_multi_1(fdc->portt, fdc->porth, fdc->port_off + - FD_YE_DATAPORT, cptr, count); + bus_space_write_multi_1(fdc->iot, fdc->ioh[FD_YE_DATAPORT], + fdc->ioff[FD_YE_DATAPORT], cptr, count); fdbcdr_wr(fdc, 0, count); /* needed? */ } } @@ -1519,6 +1538,8 @@ void fdc_release_resources(struct fdc_data *fdc) { device_t dev; + struct resource *last; + int i; dev = fdc->fdc_dev; if (fdc->fdc_intr) @@ -1528,18 +1549,15 @@ fdc_release_resources(struct fdc_data *fdc) bus_release_resource(dev, SYS_RES_IRQ, fdc->rid_irq, 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_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; + last = NULL; + for (i = 0; i < FDC_MAXREG; i++) { + if (fdc->resio[i] != NULL && fdc->resio[i] != last) { + bus_release_resource(dev, SYS_RES_IOPORT, + fdc->ridio[i], fdc->resio[i]); + last = fdc->resio[i]; + fdc->resio[i] = NULL; + } + } if (fdc->res_drq != NULL) bus_release_resource(dev, SYS_RES_DRQ, fdc->rid_drq, fdc->res_drq); @@ -1719,7 +1737,8 @@ fdc_attach(device_t dev) return (error); } error = bus_setup_intr(dev, fdc->res_irq, - INTR_TYPE_BIO | INTR_ENTROPY | INTR_FAST | INTR_MPSAFE, + INTR_TYPE_BIO | INTR_ENTROPY | INTR_MPSAFE | + ((fdc->flags & FDC_NOFAST) ? 0 : INTR_FAST), fdc_intr, fdc, &fdc->fdc_intr); if (error) { device_printf(dev, "cannot setup interrupt\n"); diff --git a/sys/dev/fdc/fdc_isa.c b/sys/dev/fdc/fdc_isa.c index fe4776660c59..a6885a9b02e3 100644 --- a/sys/dev/fdc/fdc_isa.c +++ b/sys/dev/fdc/fdc_isa.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2004 M. Warner Losh. + * Copyright (c) 2004-2005 M. Warner Losh. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -47,116 +47,73 @@ __FBSDID("$FreeBSD$"); static int fdc_isa_probe(device_t); static struct isa_pnp_id fdc_ids[] = { - {0x0007d041, "PC standard floppy disk controller"}, /* PNP0700 */ + {0x0007d041, "PC standard floppy controller"}, /* PNP0700 */ {0x0107d041, "Standard floppy controller supporting MS Device Bay Spec"}, /* PNP0701 */ {0} }; +/* + * 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. 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: + * + * 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 + * 8: 0x3f0-0x3f1,0x3f2-0x3f3,0x3f4-0x3f5,0x3f7 + * 9: 0x3f0-0x3f3,0x3f4-0x3f5,0x3f7 + * + * The following code is generic for any value of 0x3fx. It is also + * generic for all the above cases, as well as cases where things are + * even weirder. + */ int fdc_isa_alloc_resources(device_t dev, struct fdc_data *fdc) { + struct resource *res; int nports = 6; + int i, j, rid, newrid; fdc->fdc_dev = dev; - fdc->rid_ioport = 0; - fdc->rid_irq = 0; - fdc->rid_drq = 0; - fdc->rid_ctl = 1; - - /* - * 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. 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: - * - * 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 - * 8: 0x3f0-0x3f1,0x3f2-0x3f3,0x3f4-0x3f5,0x3f7 - * 9: 0x3f0-0x3f3,0x3f4-0x3f5,0x3f7 - * - * The following code is generic for any value of 0x3fx :-) - */ - - /* - * 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. - */ -again_ioport: - 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 allocate I/O port (%d ports)\n", - nports); - return (ENXIO); - } - if ((rman_get_end(fdc->res_ioport) & 0x7) == 1) { - /* Case 8 */ - bus_release_resource(dev, SYS_RES_IOPORT, fdc->rid_ioport, - fdc->res_ioport); - fdc->rid_ioport++; - goto again_ioport; - } - fdc->portt = rman_get_bustag(fdc->res_ioport); - fdc->porth = rman_get_bushandle(fdc->res_ioport); - - /* - * Handle cases 4-8 above - */ - fdc->port_off = -(fdc->porth & 0x7); - - /* - * Deal with case 6-9: FDSTS and FDDATA. - */ - if ((rman_get_end(fdc->res_ioport) & 0x7) == 3) { - fdc->rid_sts = fdc->rid_ioport + 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); + rid = 0; + for (i = 0; i < FDC_MAXREG; i++) + fdc->resio[i] = NULL; + + for (rid = 0; ; rid++) { + newrid = rid; + res = bus_alloc_resource(dev, SYS_RES_IOPORT, + &newrid, 0ul, ~0ul, nports, RF_ACTIVE); + if (res == NULL) + break; + i = rman_get_start(res); + for (j = 0; j < rman_get_size(res); j++) { + fdc->resio[i + j] = res; + fdc->ridio[i + j] = newrid; + fdc->ioff[i + j] = j; + fdc->ioh[i + j] = rman_get_bushandle(res); } - fdc->sts_off = -4; - fdc->stst = rman_get_bustag(fdc->res_sts); - fdc->stsh = rman_get_bushandle(fdc->res_sts); - } else { - fdc->res_sts = NULL; - fdc->sts_off = fdc->port_off; - fdc->stst = fdc->portt; - fdc->stsh = fdc->porth; } - - /* - * allocate the control port. For cases 1, 2, 5 and 7, we - * fake it from the ioports resource. XXX IS THIS THE RIGHT THING - * TO DO, OR SHOULD WE CREATE A NEW RID? (I think we need a new rid) - */ - fdc->rid_ctl = fdc->rid_sts + 1; - fdc->res_ctl = bus_alloc_resource_any(dev, SYS_RES_IOPORT, - &fdc->rid_ctl, RF_ACTIVE); - if (fdc->res_ctl == NULL) { - fdc->ctl_off = 7 + fdc->port_off; - fdc->res_ctl = NULL; - fdc->ctlt = fdc->portt; - fdc->ctlh = fdc->porth; - } else { - fdc->ctl_off = 0; - fdc->ctlt = rman_get_bustag(fdc->res_ctl); - fdc->ctlh = rman_get_bushandle(fdc->res_ctl); + if (fdc->resio[2] == NULL) + return (ENXIO); + fdc->iot = rman_get_bustag(fdc->resio[2]); + if (fdc->resio[7] == NULL) { + /* XXX allocate */ + fdc->resio[7] = fdc->resio[2]; + fdc->ridio[7] = fdc->ridio[2]; + fdc->ioff[7] = fdc->ioff[2] + 5; + fdc->ioh[7] = fdc->ioh[2]; } fdc->res_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &fdc->rid_irq, RF_ACTIVE | RF_SHAREABLE); - if (fdc->res_irq == 0) { + if (fdc->res_irq == NULL) { device_printf(dev, "cannot reserve interrupt line\n"); return (ENXIO); } @@ -164,7 +121,7 @@ again_ioport: if ((fdc->flags & FDC_NODMA) == 0) { fdc->res_drq = bus_alloc_resource_any(dev, SYS_RES_DRQ, &fdc->rid_drq, RF_ACTIVE | RF_SHAREABLE); - if (fdc->res_drq == 0) { + if (fdc->res_drq == NULL) { device_printf(dev, "cannot reserve DMA request line\n"); /* This is broken and doesn't work for ISA case */ fdc->flags |= FDC_NODMA; diff --git a/sys/dev/fdc/fdc_pccard.c b/sys/dev/fdc/fdc_pccard.c index baa0d013cacd..f7b05f80e419 100644 --- a/sys/dev/fdc/fdc_pccard.c +++ b/sys/dev/fdc/fdc_pccard.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2004 M. Warner Losh. + * Copyright (c) 2004-2005 M. Warner Losh. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -54,21 +54,23 @@ static const struct pccard_product fdc_pccard_products[] = { static int fdc_pccard_alloc_resources(device_t dev, struct fdc_data *fdc) { - fdc->rid_ioport = 0; - fdc->res_ioport = bus_alloc_resource(dev, SYS_RES_IOPORT, - &fdc->rid_ioport, 0ul, ~0ul, 1, RF_ACTIVE); - if (fdc->res_ioport == NULL) { + struct resource *res; + int rid, i; + + rid = 0; + res = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0ul, ~0ul, 1, + RF_ACTIVE); + if (res == NULL) { device_printf(dev, "cannot alloc I/O port range\n"); return (ENXIO); } - 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; + for (i = 0; i < FDC_MAXREG; i++) { + fdc->resio[i] = res; + fdc->ridio[i] = rid; + fdc->ioff[i] = i; + fdc->ioh[i] = rman_get_bushandle(res); + } + fdc->iot = rman_get_bustag(res); fdc->rid_irq = 0; fdc->res_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &fdc->rid_irq, @@ -101,7 +103,7 @@ fdc_pccard_attach(device_t dev) device_t child; fdc = device_get_softc(dev); - fdc->flags = FDC_NODMA; + fdc->flags = FDC_NODMA | FDC_NOFAST; fdc->fdct = FDC_NE765; error = fdc_pccard_alloc_resources(dev, fdc); if (error == 0) diff --git a/sys/dev/fdc/fdcvar.h b/sys/dev/fdc/fdcvar.h index 42ed32dcf271..5ab60a6a6443 100644 --- a/sys/dev/fdc/fdcvar.h +++ b/sys/dev/fdc/fdcvar.h @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2004 M. Warner Losh. + * Copyright (c) 2004-2005 M. Warner Losh. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -43,7 +43,8 @@ struct fdc_data { #define FDC_STAT_VALID 0x08 #define FDC_HAS_FIFO 0x10 #define FDC_NEEDS_RESET 0x20 -#define FDC_NODMA 0x40 +#define FDC_NODMA 0x40 /* Don't do DMA */ +#define FDC_NOFAST 0x80 /* Don't register isr as a fast one */ #define FDC_KTHREAD_EXIT 0x1000 /* request worker thread to stop */ #define FDC_KTHREAD_ALIVE 0x2000 /* worker thread is alive */ struct fd_data *fd; /* The active drive */ @@ -54,17 +55,14 @@ struct fdc_data { int fdc_errs; /* number of logged errors */ struct bio_queue_head head; struct bio *bp; /* active buffer */ - 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; + struct resource *res_irq, *res_drq; + int rid_irq, rid_drq; +#define FDC_MAXREG 8 + int ridio[FDC_MAXREG]; + struct resource *resio[FDC_MAXREG]; + bus_space_tag_t iot; + bus_space_handle_t ioh[FDC_MAXREG]; + int ioff[FDC_MAXREG]; void *fdc_intr; struct device *fdc_dev; struct mtx fdc_mtx; |