]> Zhao Yanbai Git Server - minix.git/commitdiff
PCI: add 64-bit BAR support
authorDavid van Moolenbroek <david@minix3.org>
Wed, 13 Jan 2010 10:52:47 +0000 (10:52 +0000)
committerDavid van Moolenbroek <david@minix3.org>
Wed, 13 Jan 2010 10:52:47 +0000 (10:52 +0000)
drivers/atl2/atl2.c
drivers/pci/pci.c
include/ibm/pci.h

index eefd3ea3a09879a89792a10e68e327cf112b53e5..144380f027daa67d09c949dd2f97ebc21b0a027e 100644 (file)
@@ -91,7 +91,7 @@ PRIVATE struct {
        { 0x0000, 0x0000 }
 };
 
-long instance;
+PRIVATE long instance;
 
 /*===========================================================================*
  *                             atl2_read_vpd                                *
@@ -524,14 +524,6 @@ PRIVATE void atl2_init(int devind)
 
        memset(&state.stat, 0, sizeof(state.stat));
 
-       /* FIXME: zero out the upper half of the 64-bit BAR. This is currently
-        * needed because the BIOS sets it to a nonzero value, and our PCI
-        * driver does not yet recognize 64-bit BARs at all. If either ever
-        * gets fixed, this will be a no-op, but for the time being, we simply
-        * hope that it will do the job.
-        */
-       pci_attr_w32(devind, PCI_BAR_2, 0);
-
        bar = pci_attr_r32(devind, PCI_BAR) & 0xfffffff0;
 
        /* FIXME: hardcoded length, as PCI doesn't expose the size, and it is
@@ -1243,7 +1235,8 @@ PRIVATE void atl2_dump(void)
  *===========================================================================*/
 PRIVATE int sef_cb_init_fresh(int type, sef_init_info_t *info)
 {
-/* Initialize the atl2 driver. */
+       /* Initialize the atl2 driver.
+        */
        u32_t inet_endpt;
        int r, devind;
 #if ATL2_FKEY
@@ -1286,6 +1279,9 @@ PRIVATE int sef_cb_init_fresh(int type, sef_init_info_t *info)
  *===========================================================================*/
 PRIVATE void sef_local_startup(void)
 {
+       /* Initialize SEF.
+        */
+
        /* Register init callbacks. */
        sef_setcb_init_fresh(sef_cb_init_fresh);
        sef_setcb_init_restart(sef_cb_init_fresh);
index 9ebf3d6d75ea675b1f9197d30c89b02bc0d6287f..859c7059b89b95653a290b113a23d31f63ca9f1b 100644 (file)
@@ -97,10 +97,11 @@ FORWARD _PROTOTYPE( void pci_intel_init, (void)                             );
 FORWARD _PROTOTYPE( void probe_bus, (int busind)                       );
 FORWARD _PROTOTYPE( int is_duplicate, (U8_t busnr, U8_t dev, U8_t func)        );
 FORWARD _PROTOTYPE( void record_irq, (int devind)                      );
-FORWARD _PROTOTYPE( void record_bars, (int devind)                     );
+FORWARD _PROTOTYPE( void record_bars_normal, (int devind)              );
 FORWARD _PROTOTYPE( void record_bars_bridge, (int devind)              );
 FORWARD _PROTOTYPE( void record_bars_cardbus, (int devind)             );
-FORWARD _PROTOTYPE( void record_bar, (int devind, int bar_nr)          );
+FORWARD _PROTOTYPE( void record_bars, (int devind, int last_reg)       );
+FORWARD _PROTOTYPE( int record_bar, (int devind, int bar_nr, int last) );
 FORWARD _PROTOTYPE( void complete_bridges, (void)                      );
 FORWARD _PROTOTYPE( void complete_bars, (void)                         );
 FORWARD _PROTOTYPE( void update_bridge4dev_io, (int devind,
@@ -870,7 +871,7 @@ printf("probe_bus(%d)\n", busind);
                        switch(headt & PHT_MASK)
                        {
                        case PHT_NORMAL:
-                               record_bars(devind);
+                               record_bars_normal(devind);
                                break;
                        case PHT_BRIDGE:
                                record_bars_bridge(devind);
@@ -993,18 +994,15 @@ int devind;
 }
 
 /*===========================================================================*
- *                             record_bars                                  *
+ *                             record_bars_normal                           *
  *===========================================================================*/
-PRIVATE void record_bars(devind)
+PRIVATE void record_bars_normal(devind)
 int devind;
 {
-       int i, j, reg, prefetch, type, clear_01, clear_23, pb_nr;
-       u32_t bar, bar2;
+       int i, j, clear_01, clear_23, pb_nr;
 
-       for (i= 0, reg= PCI_BAR; reg <= PCI_BAR_6; i++, reg += 4)
-       {
-               record_bar(devind, i);
-       }
+       /* The BAR area of normal devices is six DWORDs in size. */
+       record_bars(devind, PCI_BAR_6);
 
        /* Special case code for IDE controllers in compatibility mode */
        if (pcidev[devind].pd_baseclass == PCI_BCR_MASS_STORAGE &&
@@ -1067,8 +1065,10 @@ int devind;
 {
        u32_t base, limit, size;
 
-       record_bar(devind, 0);
-       record_bar(devind, 1);
+       /* The generic BAR area of PCI-to-PCI bridges is two DWORDs in size.
+        * It may contain up to two 32-bit BARs, or one 64-bit BAR.
+        */
+       record_bars(devind, PCI_BAR_2);
 
        base= ((pci_attr_r8_u(devind, PPB_IOBASE) & PPB_IOB_MASK) << 8) |
                (pci_attr_r16(devind, PPB_IOBASEU16) << 16);
@@ -1117,7 +1117,8 @@ int devind;
 {
        u32_t base, limit, size;
 
-       record_bar(devind, 0);
+       /* The generic BAR area of CardBus devices is one DWORD in size. */
+       record_bars(devind, PCI_BAR);
 
        base= pci_attr_r32_u(devind, CBB_MEMBASE_0);
        limit= pci_attr_r32_u(devind, CBB_MEMLIMIT_0) |
@@ -1160,17 +1161,34 @@ int devind;
        }
 }
 
+/*===========================================================================*
+ *                             record_bars                                  *
+ *===========================================================================*/
+PRIVATE void record_bars(devind, last_reg)
+{
+       int i, reg, width;
+
+       for (i= 0, reg= PCI_BAR; reg <= last_reg; i += width, reg += 4 * width)
+       {
+               width = record_bar(devind, i, reg == last_reg);
+       }
+}
+
 /*===========================================================================*
  *                             record_bar                                   *
  *===========================================================================*/
-PRIVATE void record_bar(devind, bar_nr)
+PRIVATE int record_bar(devind, bar_nr, last)
 int devind;
 int bar_nr;
+int last;
 {
-       int reg, prefetch, type, dev_bar_nr;
+       int reg, prefetch, type, dev_bar_nr, width;
        u32_t bar, bar2;
        u16_t cmd;
 
+       /* Start by assuming that this is a 32-bit bar, taking up one DWORD. */
+       width = 1;
+
        reg= PCI_BAR+4*bar_nr;
 
        bar= pci_attr_r32_u(devind, reg);
@@ -1210,6 +1228,56 @@ int bar_nr;
        }
        else
        {
+               type= (bar & PCI_BAR_TYPE);
+
+               switch(type) {
+               case PCI_TYPE_32:
+               case PCI_TYPE_32_1M:
+                       break;
+
+               case PCI_TYPE_64:
+                       /* A 64-bit BAR takes up two consecutive DWORDs. */
+                       if (last)
+                       {
+                               printf("PCI: device %d.%d.%d BAR %d extends"
+                                       " beyond designated area\n",
+                                       pcidev[devind].pd_busnr,
+                                       pcidev[devind].pd_dev,
+                                       pcidev[devind].pd_func, bar_nr);
+
+                               return width;
+                       }
+                       width++;
+
+                       bar2= pci_attr_r32_u(devind, reg+4);
+
+                       /* If the upper 32 bits of the BAR are not zero, the
+                        * memory is inaccessible to us; ignore the BAR.
+                        */
+                       if (bar2 != 0)
+                       {
+                               if (debug)
+                               {
+                                       printf("\tbar_%d: (64-bit BAR with"
+                                               " high bits set)\n", bar_nr);
+                               }
+
+                               return width;
+                       }
+
+                       break;
+
+               default:
+                       /* Ignore the BAR. */
+                       if (debug)
+                       {
+                               printf("\tbar_%d: (unknown type %x)\n",
+                                       bar_nr, type);
+                       }
+
+                       return width;
+               }
+
                /* Disable mem access before probing for BAR's size */
                cmd = pci_attr_r16(devind, PCI_CR);
                pci_attr_w16(devind, PCI_CR, cmd & ~PCI_CR_MEM_EN);
@@ -1223,20 +1291,18 @@ int bar_nr;
                pci_attr_w16(devind, PCI_CR, cmd);
 
                if (bar2 == 0)
-                       return; /* Reg. is not implemented */
+                       return width;   /* Reg. is not implemented */
 
                prefetch= !!(bar & PCI_BAR_PREFETCH);
-               type= (bar & PCI_BAR_TYPE);
                bar &= ~(u32_t)0xf;     /* Clear non-address bits */
                bar2 &= ~(u32_t)0xf;
                bar2= (~bar2)+1;
                if (debug)
                {
-                       printf("\tbar_%d: 0x%x bytes at 0x%x%s memory\n",
+                       printf("\tbar_%d: 0x%x bytes at 0x%x%s memory%s\n",
                                bar_nr, bar2, bar,
-                               prefetch ? " prefetchable" : "");
-                       if (type != 0)
-                               printf("type = 0x%x\n", type);
+                               prefetch ? " prefetchable" : "",
+                               type == PCI_TYPE_64 ? ", 64-bit" : "");
                }
 
                dev_bar_nr= pcidev[devind].pd_bar_nr++;
@@ -1250,6 +1316,8 @@ int bar_nr;
                                PBF_INCOMPLETE;
                }
        }
+
+       return width;
 }
 
 /*===========================================================================*
index 7fd0c0b8476b80311224e6ddb6ee8caa8a92df0f..cf71c6b6b25806982e7b3e7a444c89059c202945 100644 (file)
@@ -32,6 +32,9 @@ Created:      Jan 2000 by Philip Homburg <philip@cs.vu.nl>
 #define PCI_BAR                0x10    /* Base Address Register */
 #define            PCI_BAR_IO          0x00000001      /* Reg. refers to I/O space */
 #define            PCI_BAR_TYPE        0x00000006      /* Memory BAR type */
+#define                PCI_TYPE_32     0x00000000      /* 32-bit BAR */
+#define                PCI_TYPE_32_1M  0x00000002      /* 32-bit below 1MB (legacy) */
+#define                PCI_TYPE_64     0x00000004      /* 64-bit BAR */
 #define            PCI_BAR_PREFETCH    0x00000008      /* Memory is prefetchable */
 #define PCI_BAR_2      0x14    /* Base Address Register */
 #define PCI_BAR_3      0x18    /* Base Address Register */