summaryrefslogtreecommitdiffstats
path: root/sys/dev/fdc/fdc_isa.c
diff options
context:
space:
mode:
authorimp <imp@FreeBSD.org>2004-09-20 06:12:19 +0000
committerimp <imp@FreeBSD.org>2004-09-20 06:12:19 +0000
commit9ee28251177e93c5acc68b1b2fc030fa01f49769 (patch)
treea7e68e03cc17a3f41607e39f5bf58a3d435c15ee /sys/dev/fdc/fdc_isa.c
parent3c09ffb8d96ce21904234240869560df65deb8ed (diff)
downloadFreeBSD-src-9ee28251177e93c5acc68b1b2fc030fa01f49769.zip
FreeBSD-src-9ee28251177e93c5acc68b1b2fc030fa01f49769.tar.gz
das@ has a ACPI bios that lists 0x3f0-0x3f1, 0x3f2-0x3f3, 0x3f4-0x3f5
and 0x3f7. fdc_isa_alloc_resource() didn't work right in this case (it accessed FDOUT correctly due to an overflow of the first resource. It accesed FDSTS and FDDATA incorrectly via the second resource (which wound up accessing FDOUT and the tape register at 0x3f3) and badly for the CTL register (at location 0x3f4). This is a minimal fix that just 'eats' the first one if it covers two locations and has an offset of 0. This confusion lead the floppy driver to think there'd been a disk change, which uncovered a deadlock in the floppy/geom code which lead to a panic. These changes fix that by fixing the underlying resource problem, but doesn't address the potential deadlock issue that might still be there. This is a minimal fix so it can more safely be merged into 5 w/o risk for known working configurations (hence the use of the ugly goto, which reduces case 8 to case 6 w/o affecting cases 1-7). A more invasive fix that will handle more ACPI resource list diversity is in the pipeline that should kill these issues once and for all, while staying within the resources that we allocate. Tested/Reported by: das Reviewed by: njl MFC before: re->next_release_name(5.3-BETA5);
Diffstat (limited to 'sys/dev/fdc/fdc_isa.c')
-rw-r--r--sys/dev/fdc/fdc_isa.c18
1 files changed, 14 insertions, 4 deletions
diff --git a/sys/dev/fdc/fdc_isa.c b/sys/dev/fdc/fdc_isa.c
index b912771..0833fed 100644
--- a/sys/dev/fdc/fdc_isa.c
+++ b/sys/dev/fdc/fdc_isa.c
@@ -81,6 +81,7 @@ fdc_isa_alloc_resources(device_t dev, struct fdc_data *fdc)
* 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
*
* The following code is generic for any value of 0x3fx :-)
*/
@@ -90,6 +91,7 @@ fdc_isa_alloc_resources(device_t dev, struct fdc_data *fdc)
* 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) {
@@ -97,19 +99,27 @@ fdc_isa_alloc_resources(device_t dev, struct fdc_data *fdc)
nports);
return (ENXIO);
}
+ if ((rman_get_start(fdc->res_ioport) & 0x7) == 0 &&
+ rman_get_size(fdc->res_ioport) == 2) {
+ /* 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-7 above
+ * Handle cases 4-8 above
*/
fdc->port_off = -(fdc->porth & 0x7);
/*
- * Deal with case 6 and 7: FDSTS and FDSATA are in rid 1.
+ * Deal with case 6, 7, and 8: FDSTS and FDSATA are in rid 1.
*/
if (rman_get_size(fdc->res_ioport) == 2) {
- fdc->rid_sts = 1;
+ 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) {
@@ -117,7 +127,6 @@ fdc_isa_alloc_resources(device_t dev, struct fdc_data *fdc)
fdc_release_resources(fdc);
return (ENXIO);
}
- fdc->rid_ctl++;
fdc->sts_off = -4;
fdc->stst = rman_get_bustag(fdc->res_sts);
fdc->stsh = rman_get_bushandle(fdc->res_sts);
@@ -133,6 +142,7 @@ fdc_isa_alloc_resources(device_t dev, struct fdc_data *fdc)
* 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) {
OpenPOWER on IntegriCloud