Commit 06415c564fb98562a4d6b6215615deb2d1cc0dae

Authored by Marcin Slusarz
Committed by Dave Airlie
1 parent 1471ca9aa7

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>

Showing 5 changed files with 71 additions and 36 deletions Side-by-side Diff

drivers/gpu/drm/nouveau/nouveau_drv.h
... ... @@ -624,6 +624,7 @@
624 624 } debugfs;
625 625  
626 626 struct nouveau_fbdev *nfbdev;
  627 + struct apertures_struct *apertures;
627 628 };
628 629  
629 630 static inline struct drm_nouveau_private *
drivers/gpu/drm/nouveau/nouveau_fbcon.c
... ... @@ -183,7 +183,6 @@
183 183 struct drm_mode_fb_cmd mode_cmd;
184 184 struct pci_dev *pdev = dev->pdev;
185 185 struct device *device = &pdev->dev;
186   - struct apertures_struct *aper;
187 186 int size, ret;
188 187  
189 188 mode_cmd.width = sizes->surface_width;
190 189  
... ... @@ -267,26 +266,10 @@
267 266 info->fix.mmio_len = pci_resource_len(pdev, 1);
268 267  
269 268 /* Set aperture base/size for vesafb takeover */
270   - aper = info->apertures = alloc_apertures(3);
  269 + info->apertures = dev_priv->apertures;
271 270 if (!info->apertures) {
272 271 ret = -ENOMEM;
273 272 goto out_unref;
274   - }
275   -
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 273 }
291 274  
292 275 info->pixmap.size = 64*1024;
drivers/gpu/drm/nouveau/nouveau_state.c
... ... @@ -639,6 +639,43 @@
639 639 #endif
640 640 }
641 641  
  642 +static 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 +
  668 +static 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 +
642 679 int nouveau_load(struct drm_device *dev, unsigned long flags)
643 680 {
644 681 struct drm_nouveau_private *dev_priv;
... ... @@ -725,6 +762,12 @@
725 762  
726 763 NV_INFO(dev, "Detected an NV%2x generation card (0x%08x)\n",
727 764 dev_priv->card_type, reg0);
  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 + }
728 771  
729 772 /* map larger RAMIN aperture on NV40 cards */
730 773 dev_priv->ramin = NULL;
drivers/video/fbmem.c
... ... @@ -1479,11 +1479,10 @@
1479 1479 return false;
1480 1480 }
1481 1481  
1482   -static bool fb_do_apertures_overlap(struct fb_info *gen, struct fb_info *hw)
  1482 +static bool fb_do_apertures_overlap(struct apertures_struct *gena,
  1483 + struct apertures_struct *hwa)
1483 1484 {
1484 1485 int i, j;
1485   - struct apertures_struct *hwa = hw->apertures;
1486   - struct apertures_struct *gena = gen->apertures;
1487 1486 if (!hwa || !gena)
1488 1487 return false;
1489 1488  
... ... @@ -1501,6 +1500,28 @@
1501 1500 return false;
1502 1501 }
1503 1502  
  1503 +void 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 +}
  1523 +EXPORT_SYMBOL(remove_conflicting_framebuffers);
  1524 +
1504 1525 /**
1505 1526 * register_framebuffer - registers a frame buffer device
1506 1527 * @fb_info: frame buffer info structure
... ... @@ -1524,21 +1545,7 @@
1524 1545 if (fb_check_foreignness(fb_info))
1525 1546 return -ENOSYS;
1526 1547  
1527   - /* check all firmware fbs and kick off if the base addr overlaps */
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   - }
  1548 + remove_conflicting_framebuffers(fb_info->apertures, fb_info->fix.id);
1542 1549  
1543 1550 num_registered_fb++;
1544 1551 for (i = 0 ; i < FB_MAX; i++)
... ... @@ -971,6 +971,7 @@
971 971 /* drivers/video/fbmem.c */
972 972 extern int register_framebuffer(struct fb_info *fb_info);
973 973 extern int unregister_framebuffer(struct fb_info *fb_info);
  974 +extern void remove_conflicting_framebuffers(struct apertures_struct *a, const char *name);
974 975 extern int fb_prepare_logo(struct fb_info *fb_info, int rotate);
975 976 extern int fb_show_logo(struct fb_info *fb_info, int rotate);
976 977 extern char* fb_get_buffer_offset(struct fb_info *info, struct fb_pixmap *buf, u32 size);