diff options
author | David S. Miller <davem@sunset.davemloft.net> | 2007-07-28 01:31:46 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2007-07-30 03:27:33 -0400 |
commit | c7f439b99efbea74c70a5531f92566db5a6731f2 (patch) | |
tree | 7053ceffa23d54670862e14d0bc2eec9d5d42427 /drivers/video/ffb.c | |
parent | a0afaa6ab12cf696d170c22a8fdfd88c3e33555c (diff) |
[VIDEO]: Fix OOPS in all SBUS framebuffer drivers.
All of these drivers use a silly:
struct all_info {
struct fb_info info;
struct foo_par par;
};
struct all_info *all = kzalloc(sizeof(*all), GFP_KERNEL);
all->info.par = &all->par;
etc. etc. code sequence, basically replicating the provided
framebuffer_alloc()/framebuffer_release(), and doing it badly.
Not only is this massive code duplication, it also caused a
bug in that we weren't setting the fb_info->device pointer
which results in an OOPS when fb_is_primary_device() runs.
Fix all of this by using framebuffer_{alloc,release}() and
passing in "&of_device->dev" as the device pointer.
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/video/ffb.c')
-rw-r--r-- | drivers/video/ffb.c | 170 |
1 files changed, 79 insertions, 91 deletions
diff --git a/drivers/video/ffb.c b/drivers/video/ffb.c index 3f6c98fad437..4b520b573911 100644 --- a/drivers/video/ffb.c +++ b/drivers/video/ffb.c | |||
@@ -371,6 +371,8 @@ struct ffb_par { | |||
371 | unsigned long fbsize; | 371 | unsigned long fbsize; |
372 | 372 | ||
373 | int board_type; | 373 | int board_type; |
374 | |||
375 | u32 pseudo_palette[16]; | ||
374 | }; | 376 | }; |
375 | 377 | ||
376 | static void FFBFifo(struct ffb_par *par, int n) | 378 | static void FFBFifo(struct ffb_par *par, int n) |
@@ -900,75 +902,67 @@ ffb_init_fix(struct fb_info *info) | |||
900 | info->fix.accel = FB_ACCEL_SUN_CREATOR; | 902 | info->fix.accel = FB_ACCEL_SUN_CREATOR; |
901 | } | 903 | } |
902 | 904 | ||
903 | struct all_info { | 905 | static int __devinit ffb_probe(struct of_device *op, const struct of_device_id *match) |
904 | struct fb_info info; | ||
905 | struct ffb_par par; | ||
906 | u32 pseudo_palette[16]; | ||
907 | }; | ||
908 | |||
909 | static int ffb_init_one(struct of_device *op) | ||
910 | { | 906 | { |
911 | struct device_node *dp = op->node; | 907 | struct device_node *dp = op->node; |
912 | struct ffb_fbc __iomem *fbc; | 908 | struct ffb_fbc __iomem *fbc; |
913 | struct ffb_dac __iomem *dac; | 909 | struct ffb_dac __iomem *dac; |
914 | struct all_info *all; | 910 | struct fb_info *info; |
915 | int err; | 911 | struct ffb_par *par; |
916 | u32 dac_pnum, dac_rev, dac_mrev; | 912 | u32 dac_pnum, dac_rev, dac_mrev; |
913 | int err; | ||
917 | 914 | ||
918 | all = kzalloc(sizeof(*all), GFP_KERNEL); | 915 | info = framebuffer_alloc(sizeof(struct ffb_par), &op->dev); |
919 | if (!all) | ||
920 | return -ENOMEM; | ||
921 | 916 | ||
922 | spin_lock_init(&all->par.lock); | 917 | err = -ENOMEM; |
923 | all->par.fbc = of_ioremap(&op->resource[2], 0, | 918 | if (!info) |
924 | sizeof(struct ffb_fbc), "ffb fbc"); | 919 | goto out_err; |
925 | if (!all->par.fbc) { | ||
926 | kfree(all); | ||
927 | return -ENOMEM; | ||
928 | } | ||
929 | 920 | ||
930 | all->par.dac = of_ioremap(&op->resource[1], 0, | 921 | par = info->par; |
931 | sizeof(struct ffb_dac), "ffb dac"); | 922 | |
932 | if (!all->par.dac) { | 923 | spin_lock_init(&par->lock); |
933 | of_iounmap(&op->resource[2], | 924 | par->fbc = of_ioremap(&op->resource[2], 0, |
934 | all->par.fbc, sizeof(struct ffb_fbc)); | 925 | sizeof(struct ffb_fbc), "ffb fbc"); |
935 | kfree(all); | 926 | if (!par->fbc) |
936 | return -ENOMEM; | 927 | goto out_release_fb; |
937 | } | 928 | |
929 | par->dac = of_ioremap(&op->resource[1], 0, | ||
930 | sizeof(struct ffb_dac), "ffb dac"); | ||
931 | if (!par->dac) | ||
932 | goto out_unmap_fbc; | ||
938 | 933 | ||
939 | all->par.rop_cache = FFB_ROP_NEW; | 934 | par->rop_cache = FFB_ROP_NEW; |
940 | all->par.physbase = op->resource[0].start; | 935 | par->physbase = op->resource[0].start; |
941 | 936 | ||
942 | /* Don't mention copyarea, so SCROLL_REDRAW is always | 937 | /* Don't mention copyarea, so SCROLL_REDRAW is always |
943 | * used. It is the fastest on this chip. | 938 | * used. It is the fastest on this chip. |
944 | */ | 939 | */ |
945 | all->info.flags = (FBINFO_DEFAULT | | 940 | info->flags = (FBINFO_DEFAULT | |
946 | /* FBINFO_HWACCEL_COPYAREA | */ | 941 | /* FBINFO_HWACCEL_COPYAREA | */ |
947 | FBINFO_HWACCEL_FILLRECT | | 942 | FBINFO_HWACCEL_FILLRECT | |
948 | FBINFO_HWACCEL_IMAGEBLIT); | 943 | FBINFO_HWACCEL_IMAGEBLIT); |
949 | all->info.fbops = &ffb_ops; | 944 | |
950 | all->info.screen_base = (char *) all->par.physbase + FFB_DFB24_POFF; | 945 | info->fbops = &ffb_ops; |
951 | all->info.par = &all->par; | 946 | |
952 | all->info.pseudo_palette = all->pseudo_palette; | 947 | info->screen_base = (char *) par->physbase + FFB_DFB24_POFF; |
953 | 948 | info->pseudo_palette = par->pseudo_palette; | |
954 | sbusfb_fill_var(&all->info.var, dp->node, 32); | 949 | |
955 | all->par.fbsize = PAGE_ALIGN(all->info.var.xres * | 950 | sbusfb_fill_var(&info->var, dp->node, 32); |
956 | all->info.var.yres * | 951 | par->fbsize = PAGE_ALIGN(info->var.xres * info->var.yres * 4); |
957 | 4); | 952 | ffb_fixup_var_rgb(&info->var); |
958 | ffb_fixup_var_rgb(&all->info.var); | 953 | |
959 | 954 | info->var.accel_flags = FB_ACCELF_TEXT; | |
960 | all->info.var.accel_flags = FB_ACCELF_TEXT; | ||
961 | 955 | ||
962 | if (!strcmp(dp->name, "SUNW,afb")) | 956 | if (!strcmp(dp->name, "SUNW,afb")) |
963 | all->par.flags |= FFB_FLAG_AFB; | 957 | par->flags |= FFB_FLAG_AFB; |
964 | 958 | ||
965 | all->par.board_type = of_getintprop_default(dp, "board_type", 0); | 959 | par->board_type = of_getintprop_default(dp, "board_type", 0); |
966 | 960 | ||
967 | fbc = all->par.fbc; | 961 | fbc = par->fbc; |
968 | if ((upa_readl(&fbc->ucsr) & FFB_UCSR_ALL_ERRORS) != 0) | 962 | if ((upa_readl(&fbc->ucsr) & FFB_UCSR_ALL_ERRORS) != 0) |
969 | upa_writel(FFB_UCSR_ALL_ERRORS, &fbc->ucsr); | 963 | upa_writel(FFB_UCSR_ALL_ERRORS, &fbc->ucsr); |
970 | 964 | ||
971 | dac = all->par.dac; | 965 | dac = par->dac; |
972 | upa_writel(FFB_DAC_DID, &dac->type); | 966 | upa_writel(FFB_DAC_DID, &dac->type); |
973 | dac_pnum = upa_readl(&dac->value); | 967 | dac_pnum = upa_readl(&dac->value); |
974 | dac_rev = (dac_pnum & FFB_DAC_DID_REV) >> FFB_DAC_DID_REV_SHIFT; | 968 | dac_rev = (dac_pnum & FFB_DAC_DID_REV) >> FFB_DAC_DID_REV_SHIFT; |
@@ -985,76 +979,70 @@ static int ffb_init_one(struct of_device *op) | |||
985 | * cursor logic. We identify Pacifica 1 as not Pacifica 2, the | 979 | * cursor logic. We identify Pacifica 1 as not Pacifica 2, the |
986 | * latter having a part number value of 0x236e. | 980 | * latter having a part number value of 0x236e. |
987 | */ | 981 | */ |
988 | if ((all->par.flags & FFB_FLAG_AFB) || dac_pnum == 0x236e) { | 982 | if ((par->flags & FFB_FLAG_AFB) || dac_pnum == 0x236e) { |
989 | all->par.flags &= ~FFB_FLAG_INVCURSOR; | 983 | par->flags &= ~FFB_FLAG_INVCURSOR; |
990 | } else { | 984 | } else { |
991 | if (dac_mrev < 3) | 985 | if (dac_mrev < 3) |
992 | all->par.flags |= FFB_FLAG_INVCURSOR; | 986 | par->flags |= FFB_FLAG_INVCURSOR; |
993 | } | 987 | } |
994 | 988 | ||
995 | ffb_switch_from_graph(&all->par); | 989 | ffb_switch_from_graph(par); |
996 | 990 | ||
997 | /* Unblank it just to be sure. When there are multiple | 991 | /* Unblank it just to be sure. When there are multiple |
998 | * FFB/AFB cards in the system, or it is not the OBP | 992 | * FFB/AFB cards in the system, or it is not the OBP |
999 | * chosen console, it will have video outputs off in | 993 | * chosen console, it will have video outputs off in |
1000 | * the DAC. | 994 | * the DAC. |
1001 | */ | 995 | */ |
1002 | ffb_blank(0, &all->info); | 996 | ffb_blank(0, info); |
1003 | |||
1004 | if (fb_alloc_cmap(&all->info.cmap, 256, 0)) { | ||
1005 | printk(KERN_ERR "ffb: Could not allocate color map.\n"); | ||
1006 | of_iounmap(&op->resource[2], | ||
1007 | all->par.fbc, sizeof(struct ffb_fbc)); | ||
1008 | of_iounmap(&op->resource[1], | ||
1009 | all->par.dac, sizeof(struct ffb_dac)); | ||
1010 | kfree(all); | ||
1011 | return -ENOMEM; | ||
1012 | } | ||
1013 | 997 | ||
1014 | ffb_init_fix(&all->info); | 998 | if (fb_alloc_cmap(&info->cmap, 256, 0)) |
1015 | 999 | goto out_unmap_dac; | |
1016 | err = register_framebuffer(&all->info); | 1000 | |
1017 | if (err < 0) { | 1001 | ffb_init_fix(info); |
1018 | printk(KERN_ERR "ffb: Could not register framebuffer.\n"); | ||
1019 | fb_dealloc_cmap(&all->info.cmap); | ||
1020 | of_iounmap(&op->resource[2], | ||
1021 | all->par.fbc, sizeof(struct ffb_fbc)); | ||
1022 | of_iounmap(&op->resource[1], | ||
1023 | all->par.dac, sizeof(struct ffb_dac)); | ||
1024 | kfree(all); | ||
1025 | return err; | ||
1026 | } | ||
1027 | 1002 | ||
1028 | dev_set_drvdata(&op->dev, all); | 1003 | err = register_framebuffer(info); |
1004 | if (err < 0) | ||
1005 | goto out_dealloc_cmap; | ||
1006 | |||
1007 | dev_set_drvdata(&op->dev, info); | ||
1029 | 1008 | ||
1030 | printk("%s: %s at %016lx, type %d, " | 1009 | printk("%s: %s at %016lx, type %d, " |
1031 | "DAC pnum[%x] rev[%d] manuf_rev[%d]\n", | 1010 | "DAC pnum[%x] rev[%d] manuf_rev[%d]\n", |
1032 | dp->full_name, | 1011 | dp->full_name, |
1033 | ((all->par.flags & FFB_FLAG_AFB) ? "AFB" : "FFB"), | 1012 | ((par->flags & FFB_FLAG_AFB) ? "AFB" : "FFB"), |
1034 | all->par.physbase, all->par.board_type, | 1013 | par->physbase, par->board_type, |
1035 | dac_pnum, dac_rev, dac_mrev); | 1014 | dac_pnum, dac_rev, dac_mrev); |
1036 | 1015 | ||
1037 | return 0; | 1016 | return 0; |
1038 | } | ||
1039 | 1017 | ||
1040 | static int __devinit ffb_probe(struct of_device *dev, const struct of_device_id *match) | 1018 | out_dealloc_cmap: |
1041 | { | 1019 | fb_dealloc_cmap(&info->cmap); |
1042 | struct of_device *op = to_of_device(&dev->dev); | 1020 | |
1021 | out_unmap_dac: | ||
1022 | of_iounmap(&op->resource[2], par->fbc, sizeof(struct ffb_fbc)); | ||
1023 | |||
1024 | out_unmap_fbc: | ||
1025 | of_iounmap(&op->resource[2], par->fbc, sizeof(struct ffb_fbc)); | ||
1026 | |||
1027 | out_release_fb: | ||
1028 | framebuffer_release(info); | ||
1043 | 1029 | ||
1044 | return ffb_init_one(op); | 1030 | out_err: |
1031 | return err; | ||
1045 | } | 1032 | } |
1046 | 1033 | ||
1047 | static int __devexit ffb_remove(struct of_device *op) | 1034 | static int __devexit ffb_remove(struct of_device *op) |
1048 | { | 1035 | { |
1049 | struct all_info *all = dev_get_drvdata(&op->dev); | 1036 | struct fb_info *info = dev_get_drvdata(&op->dev); |
1037 | struct ffb_par *par = info->par; | ||
1050 | 1038 | ||
1051 | unregister_framebuffer(&all->info); | 1039 | unregister_framebuffer(info); |
1052 | fb_dealloc_cmap(&all->info.cmap); | 1040 | fb_dealloc_cmap(&info->cmap); |
1053 | 1041 | ||
1054 | of_iounmap(&op->resource[2], all->par.fbc, sizeof(struct ffb_fbc)); | 1042 | of_iounmap(&op->resource[2], par->fbc, sizeof(struct ffb_fbc)); |
1055 | of_iounmap(&op->resource[1], all->par.dac, sizeof(struct ffb_dac)); | 1043 | of_iounmap(&op->resource[1], par->dac, sizeof(struct ffb_dac)); |
1056 | 1044 | ||
1057 | kfree(all); | 1045 | framebuffer_release(info); |
1058 | 1046 | ||
1059 | dev_set_drvdata(&op->dev, NULL); | 1047 | dev_set_drvdata(&op->dev, NULL); |
1060 | 1048 | ||