aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarcin Slusarz <marcin.slusarz@gmail.com>2010-05-16 11:29:56 -0400
committerDave Airlie <airlied@redhat.com>2010-05-18 02:19:28 -0400
commit06415c564fb98562a4d6b6215615deb2d1cc0dae (patch)
tree93982221251bc68eb292a07da72220a0c90d94f0
parent1471ca9aa71cd37b6a7476bb6f06a3a8622ea1bd (diff)
fbmem, drm/nouveau: kick firmware framebuffers as soon as possible
Currently vesafb/efifb/... is kicked when hardware driver is registering framebuffer. To do it hardware must be fully functional, so there's a short window between start of initialisation and framebuffer registration when two drivers touch the hardware. Unfortunately sometimes it breaks nouveau initialisation. Fix it by kicking firmware driver(s) before we start touching the hardware. Reported-by: Didier Spaier <didier.spaier@epsm.fr> Tested-by: Didier Spaier <didier.spaier@epsm.fr> Signed-off-by: Marcin Slusarz <marcin.slusarz@gmail.com> Cc: Ben Skeggs <bskeggs@redhat.com> Cc: Peter Jones <pjones@redhat.com> Cc: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Dave Airlie <airlied@redhat.com>
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drv.h1
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_fbcon.c19
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_state.c43
-rw-r--r--drivers/video/fbmem.c43
-rw-r--r--include/linux/fb.h1
5 files changed, 71 insertions, 36 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h
index 5b47b79f45e8..94d8dd27bde8 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.h
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.h
@@ -624,6 +624,7 @@ struct drm_nouveau_private {
624 } debugfs; 624 } debugfs;
625 625
626 struct nouveau_fbdev *nfbdev; 626 struct nouveau_fbdev *nfbdev;
627 struct apertures_struct *apertures;
627}; 628};
628 629
629static inline struct drm_nouveau_private * 630static inline struct drm_nouveau_private *
diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
index 292c7ff95105..2c2199329cc1 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c
+++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
@@ -183,7 +183,6 @@ nouveau_fbcon_create(struct nouveau_fbdev *nfbdev,
183 struct drm_mode_fb_cmd mode_cmd; 183 struct drm_mode_fb_cmd mode_cmd;
184 struct pci_dev *pdev = dev->pdev; 184 struct pci_dev *pdev = dev->pdev;
185 struct device *device = &pdev->dev; 185 struct device *device = &pdev->dev;
186 struct apertures_struct *aper;
187 int size, ret; 186 int size, ret;
188 187
189 mode_cmd.width = sizes->surface_width; 188 mode_cmd.width = sizes->surface_width;
@@ -267,28 +266,12 @@ nouveau_fbcon_create(struct nouveau_fbdev *nfbdev,
267 info->fix.mmio_len = pci_resource_len(pdev, 1); 266 info->fix.mmio_len = pci_resource_len(pdev, 1);
268 267
269 /* Set aperture base/size for vesafb takeover */ 268 /* Set aperture base/size for vesafb takeover */
270 aper = info->apertures = alloc_apertures(3); 269 info->apertures = dev_priv->apertures;
271 if (!info->apertures) { 270 if (!info->apertures) {
272 ret = -ENOMEM; 271 ret = -ENOMEM;
273 goto out_unref; 272 goto out_unref;
274 } 273 }
275 274
276 aper->ranges[0].base = pci_resource_start(pdev, 1);
277 aper->ranges[0].size = pci_resource_len(pdev, 1);
278 aper->count = 1;
279
280 if (pci_resource_len(pdev, 2)) {
281 aper->ranges[aper->count].base = pci_resource_start(pdev, 2);
282 aper->ranges[aper->count].size = pci_resource_len(pdev, 2);
283 aper->count++;
284 }
285
286 if (pci_resource_len(pdev, 3)) {
287 aper->ranges[aper->count].base = pci_resource_start(pdev, 3);
288 aper->ranges[aper->count].size = pci_resource_len(pdev, 3);
289 aper->count++;
290 }
291
292 info->pixmap.size = 64*1024; 275 info->pixmap.size = 64*1024;
293 info->pixmap.buf_align = 8; 276 info->pixmap.buf_align = 8;
294 info->pixmap.access_align = 32; 277 info->pixmap.access_align = 32;
diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c
index 92100a9678ba..75c5c465e08e 100644
--- a/drivers/gpu/drm/nouveau/nouveau_state.c
+++ b/drivers/gpu/drm/nouveau/nouveau_state.c
@@ -639,6 +639,43 @@ static void nouveau_OF_copy_vbios_to_ramin(struct drm_device *dev)
639#endif 639#endif
640} 640}
641 641
642static struct apertures_struct *nouveau_get_apertures(struct drm_device *dev)
643{
644 struct pci_dev *pdev = dev->pdev;
645 struct apertures_struct *aper = alloc_apertures(3);
646 if (!aper)
647 return NULL;
648
649 aper->ranges[0].base = pci_resource_start(pdev, 1);
650 aper->ranges[0].size = pci_resource_len(pdev, 1);
651 aper->count = 1;
652
653 if (pci_resource_len(pdev, 2)) {
654 aper->ranges[aper->count].base = pci_resource_start(pdev, 2);
655 aper->ranges[aper->count].size = pci_resource_len(pdev, 2);
656 aper->count++;
657 }
658
659 if (pci_resource_len(pdev, 3)) {
660 aper->ranges[aper->count].base = pci_resource_start(pdev, 3);
661 aper->ranges[aper->count].size = pci_resource_len(pdev, 3);
662 aper->count++;
663 }
664
665 return aper;
666}
667
668static int nouveau_remove_conflicting_drivers(struct drm_device *dev)
669{
670 struct drm_nouveau_private *dev_priv = dev->dev_private;
671 dev_priv->apertures = nouveau_get_apertures(dev);
672 if (!dev_priv->apertures)
673 return -ENOMEM;
674
675 remove_conflicting_framebuffers(dev_priv->apertures, "nouveaufb");
676 return 0;
677}
678
642int nouveau_load(struct drm_device *dev, unsigned long flags) 679int nouveau_load(struct drm_device *dev, unsigned long flags)
643{ 680{
644 struct drm_nouveau_private *dev_priv; 681 struct drm_nouveau_private *dev_priv;
@@ -726,6 +763,12 @@ int nouveau_load(struct drm_device *dev, unsigned long flags)
726 NV_INFO(dev, "Detected an NV%2x generation card (0x%08x)\n", 763 NV_INFO(dev, "Detected an NV%2x generation card (0x%08x)\n",
727 dev_priv->card_type, reg0); 764 dev_priv->card_type, reg0);
728 765
766 if (drm_core_check_feature(dev, DRIVER_MODESET)) {
767 int ret = nouveau_remove_conflicting_drivers(dev);
768 if (ret)
769 return ret;
770 }
771
729 /* map larger RAMIN aperture on NV40 cards */ 772 /* map larger RAMIN aperture on NV40 cards */
730 dev_priv->ramin = NULL; 773 dev_priv->ramin = NULL;
731 if (dev_priv->card_type >= NV_40) { 774 if (dev_priv->card_type >= NV_40) {
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c
index 03f2dc2470b5..7cfcd716fd5f 100644
--- a/drivers/video/fbmem.c
+++ b/drivers/video/fbmem.c
@@ -1479,11 +1479,10 @@ static bool apertures_overlap(struct aperture *gen, struct aperture *hw)
1479 return false; 1479 return false;
1480} 1480}
1481 1481
1482static bool fb_do_apertures_overlap(struct fb_info *gen, struct fb_info *hw) 1482static bool fb_do_apertures_overlap(struct apertures_struct *gena,
1483 struct apertures_struct *hwa)
1483{ 1484{
1484 int i, j; 1485 int i, j;
1485 struct apertures_struct *hwa = hw->apertures;
1486 struct apertures_struct *gena = gen->apertures;
1487 if (!hwa || !gena) 1486 if (!hwa || !gena)
1488 return false; 1487 return false;
1489 1488
@@ -1501,6 +1500,28 @@ static bool fb_do_apertures_overlap(struct fb_info *gen, struct fb_info *hw)
1501 return false; 1500 return false;
1502} 1501}
1503 1502
1503void remove_conflicting_framebuffers(struct apertures_struct *a, const char *name)
1504{
1505 int i;
1506
1507 /* check all firmware fbs and kick off if the base addr overlaps */
1508 for (i = 0 ; i < FB_MAX; i++) {
1509 if (!registered_fb[i])
1510 continue;
1511
1512 if (!(registered_fb[i]->flags & FBINFO_MISC_FIRMWARE))
1513 continue;
1514
1515 if (fb_do_apertures_overlap(registered_fb[i]->apertures, a)) {
1516 printk(KERN_ERR "fb: conflicting fb hw usage "
1517 "%s vs %s - removing generic driver\n",
1518 name, registered_fb[i]->fix.id);
1519 unregister_framebuffer(registered_fb[i]);
1520 }
1521 }
1522}
1523EXPORT_SYMBOL(remove_conflicting_framebuffers);
1524
1504/** 1525/**
1505 * register_framebuffer - registers a frame buffer device 1526 * register_framebuffer - registers a frame buffer device
1506 * @fb_info: frame buffer info structure 1527 * @fb_info: frame buffer info structure
@@ -1524,21 +1545,7 @@ register_framebuffer(struct fb_info *fb_info)
1524 if (fb_check_foreignness(fb_info)) 1545 if (fb_check_foreignness(fb_info))
1525 return -ENOSYS; 1546 return -ENOSYS;
1526 1547
1527 /* check all firmware fbs and kick off if the base addr overlaps */ 1548 remove_conflicting_framebuffers(fb_info->apertures, fb_info->fix.id);
1528 for (i = 0 ; i < FB_MAX; i++) {
1529 if (!registered_fb[i])
1530 continue;
1531
1532 if (registered_fb[i]->flags & FBINFO_MISC_FIRMWARE) {
1533 if (fb_do_apertures_overlap(registered_fb[i], fb_info)) {
1534 printk(KERN_ERR "fb: conflicting fb hw usage "
1535 "%s vs %s - removing generic driver\n",
1536 fb_info->fix.id,
1537 registered_fb[i]->fix.id);
1538 unregister_framebuffer(registered_fb[i]);
1539 }
1540 }
1541 }
1542 1549
1543 num_registered_fb++; 1550 num_registered_fb++;
1544 for (i = 0 ; i < FB_MAX; i++) 1551 for (i = 0 ; i < FB_MAX; i++)
diff --git a/include/linux/fb.h b/include/linux/fb.h
index de5ff5fa8380..f88e2549123d 100644
--- a/include/linux/fb.h
+++ b/include/linux/fb.h
@@ -971,6 +971,7 @@ extern ssize_t fb_sys_write(struct fb_info *info, const char __user *buf,
971/* drivers/video/fbmem.c */ 971/* drivers/video/fbmem.c */
972extern int register_framebuffer(struct fb_info *fb_info); 972extern int register_framebuffer(struct fb_info *fb_info);
973extern int unregister_framebuffer(struct fb_info *fb_info); 973extern int unregister_framebuffer(struct fb_info *fb_info);
974extern void remove_conflicting_framebuffers(struct apertures_struct *a, const char *name);
974extern int fb_prepare_logo(struct fb_info *fb_info, int rotate); 975extern int fb_prepare_logo(struct fb_info *fb_info, int rotate);
975extern int fb_show_logo(struct fb_info *fb_info, int rotate); 976extern int fb_show_logo(struct fb_info *fb_info, int rotate);
976extern char* fb_get_buffer_offset(struct fb_info *info, struct fb_pixmap *buf, u32 size); 977extern char* fb_get_buffer_offset(struct fb_info *info, struct fb_pixmap *buf, u32 size);