From: David van Moolenbroek Date: Wed, 13 Jan 2010 10:52:47 +0000 (+0000) Subject: PCI: add 64-bit BAR support X-Git-Tag: v3.1.6~90 X-Git-Url: http://zhaoyanbai.com/repos/?a=commitdiff_plain;h=6a5660a4310461b145a1175e46c76930ac0a0a6c;p=minix.git PCI: add 64-bit BAR support --- diff --git a/drivers/atl2/atl2.c b/drivers/atl2/atl2.c index eefd3ea3a..144380f02 100644 --- a/drivers/atl2/atl2.c +++ b/drivers/atl2/atl2.c @@ -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); diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 9ebf3d6d7..859c7059b 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -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; } /*===========================================================================* diff --git a/include/ibm/pci.h b/include/ibm/pci.h index 7fd0c0b84..cf71c6b6b 100644 --- a/include/ibm/pci.h +++ b/include/ibm/pci.h @@ -32,6 +32,9 @@ Created: Jan 2000 by Philip Homburg #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 */