From: David van Moolenbroek Date: Thu, 1 Jul 2010 09:10:16 +0000 (+0000) Subject: PCI: expose BAR sizes X-Git-Tag: v3.1.8~303 X-Git-Url: http://zhaoyanbai.com/repos/%22http:/www.isc.org/static/host.html?a=commitdiff_plain;h=2488cc6442a4f7db2f208c4c0175cfd26d8e0e3a;p=minix.git PCI: expose BAR sizes --- diff --git a/drivers/atl2/atl2.c b/drivers/atl2/atl2.c index 670949006..381eb56b9 100644 --- a/drivers/atl2/atl2.c +++ b/drivers/atl2/atl2.c @@ -38,6 +38,7 @@ PRIVATE struct { int hook_id; /* IRQ hook ID */ int mode; /* datalink mode */ char *base; /* base address of memory-mapped registers */ + u32_t size; /* size of memory-mapped area */ u32_t hwaddr[2]; /* MAC address, in register representation */ u8_t *txd_base; /* local address of TxD ring buffer base */ @@ -514,7 +515,7 @@ PRIVATE void atl2_init(int devind) /* Initialize the device. */ u32_t bar; - int r; + int r, flag; /* Initialize global state. */ state.devind = devind; @@ -524,12 +525,13 @@ PRIVATE void atl2_init(int devind) memset(&state.stat, 0, sizeof(state.stat)); - bar = pci_attr_r32(devind, PCI_BAR) & 0xfffffff0; + if ((r = pci_get_bar(devind, PCI_BAR, &bar, &state.size, &flag)) != OK) + panic("unable to retrieve bar: %d", r); - /* FIXME: hardcoded length, as PCI doesn't expose the size, and it is - * not our job to compute the size from the BAR ourselves. - */ - state.base = vm_map_phys(SELF, (void *) bar, ATL2_MMAP_SIZE); + if (state.size < ATL2_MIN_MMAP_SIZE || flag) + panic("invalid register bar"); + + state.base = vm_map_phys(SELF, (void *) bar, state.size); if (state.base == MAP_FAILED) panic("unable to map in registers"); @@ -1214,7 +1216,7 @@ PRIVATE void sef_cb_signal_handler(int signo) free_contig(state.rxd_base_u, state.rxd_align + ATL2_RXD_COUNT * ATL2_RXD_SIZE); - vm_unmap_phys(SELF, state.base, ATL2_MMAP_SIZE); + vm_unmap_phys(SELF, state.base, state.size); /* We cannot free the PCI device at this time. */ diff --git a/drivers/atl2/atl2.h b/drivers/atl2/atl2.h index 06812bcd0..85c5e4362 100644 --- a/drivers/atl2/atl2.h +++ b/drivers/atl2/atl2.h @@ -1,6 +1,6 @@ /* Attansic/Atheros L2 FastEthernet driver, by D.C. van Moolenbroek */ -#define ATL2_MMAP_SIZE 0x40000 /* memory-mapped registers */ +#define ATL2_MIN_MMAP_SIZE 0x1608 /* min. register memory size */ /* The first three are configurable to a certain extent; the last is not. */ #define ATL2_TXD_BUFSIZE 8192 /* TxD ring buffer size */ diff --git a/drivers/pci/main.c b/drivers/pci/main.c index 8ddd0cc4d..4d2ba273d 100644 --- a/drivers/pci/main.c +++ b/drivers/pci/main.c @@ -23,6 +23,7 @@ FORWARD _PROTOTYPE( void do_attr_r32, (message *mp) ); FORWARD _PROTOTYPE( void do_attr_w8, (message *mp) ); FORWARD _PROTOTYPE( void do_attr_w16, (message *mp) ); FORWARD _PROTOTYPE( void do_attr_w32, (message *mp) ); +FORWARD _PROTOTYPE( void do_get_bar, (message *mp) ); FORWARD _PROTOTYPE( void do_rescan_bus, (message *mp) ); FORWARD _PROTOTYPE( void reply, (message *mp, int result) ); FORWARD _PROTOTYPE( struct rs_pci *find_acl, (int endpoint) ); @@ -77,6 +78,7 @@ int main(void) case BUSC_PCI_SLOT_NAME_S: do_slot_name_s(&m); break; case BUSC_PCI_SET_ACL: do_set_acl(&m); break; case BUSC_PCI_DEL_ACL: do_del_acl(&m); break; + case BUSC_PCI_GET_BAR: do_get_bar(&m); break; default: printf("PCI: got message from %d, type %d\n", m.m_source, m.m_type); @@ -562,6 +564,32 @@ message *mp; } } +PRIVATE void do_get_bar(mp) +message *mp; +{ + int r, devind, port, ioflag; + u32_t base, size; + + devind= mp->BUSC_PGB_DEVIND; + port= mp->BUSC_PGB_PORT; + + mp->m_type= pci_get_bar_s(devind, port, &base, &size, &ioflag); + + if (mp->m_type == OK) + { + mp->BUSC_PGB_BASE= base; + mp->BUSC_PGB_SIZE= size; + mp->BUSC_PGB_IOFLAG= ioflag; + } + + r= send(mp->m_source, mp); + if (r != 0) + { + printf("do_get_bar: unable to send to %d: %d\n", + mp->m_source, r); + } +} + PRIVATE void do_rescan_bus(mp) message *mp; { diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index b72f6eb31..90971452b 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -516,6 +516,36 @@ PUBLIC char *pci_dev_name(u16_t vid, u16_t did) return NULL; } +/*===========================================================================* + * pci_get_bar_s * + *===========================================================================*/ +PUBLIC int pci_get_bar_s(int devind, int port, u32_t *base, u32_t *size, + int *ioflag) +{ + int i, reg; + + if (devind < 0 || devind >= nr_pcidev) + return EINVAL; + + for (i= 0; i < pcidev[devind].pd_bar_nr; i++) + { + reg= PCI_BAR+4*pcidev[devind].pd_bar[i].pb_nr; + + if (reg == port) + { + if (pcidev[devind].pd_bar[i].pb_flags & PBF_INCOMPLETE) + return EINVAL; + + *base= pcidev[devind].pd_bar[i].pb_base; + *size= pcidev[devind].pd_bar[i].pb_size; + *ioflag= + !!(pcidev[devind].pd_bar[i].pb_flags & PBF_IO); + return OK; + } + } + return EINVAL; +} + /*===========================================================================* * pci_attr_r8_s * *===========================================================================*/ diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 9f91f3191..af0a06653 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -105,6 +105,8 @@ _PROTOTYPE( int pci_next_dev_a, (struct rs_pci *aclp, int *devindp, _PROTOTYPE( int pci_attr_r8_s, (int devind, int port, u8_t *vp) ); _PROTOTYPE( int pci_attr_r32_s, (int devind, int port, u32_t *vp) ); +_PROTOTYPE( int pci_get_bar_s, (int devind, int port, u32_t *base, + u32_t *size, int *ioflag) ); _PROTOTYPE( int pci_slot_name_s, (int devind, char **cpp) ); _PROTOTYPE( int pci_ids_s, (int devind, u16_t *vidp, u16_t *didp) ); diff --git a/include/minix/com.h b/include/minix/com.h index 5a184f4a5..fe7a25a97 100644 --- a/include/minix/com.h +++ b/include/minix/com.h @@ -171,6 +171,14 @@ #define BUSC_PCI_DEL_ACL (BUSC_RQ_BASE + 18) /* Delete the ACL of a * driver */ +#define BUSC_PCI_GET_BAR (BUSC_RQ_BASE + 19) /* Get Base Address + * Register properties + */ +#define BUSC_PGB_DEVIND m2_i1 /* device index */ +#define BUSC_PGB_PORT m2_i2 /* port (BAR offset) */ +#define BUSC_PGB_BASE m2_l1 /* BAR base address */ +#define BUSC_PGB_SIZE m2_l2 /* BAR size */ +#define BUSC_PGB_IOFLAG m2_i1 /* I/O space? */ #define IOMMU_MAP (BUSC_RQ_BASE + 32) /* Ask IOMMU to map * a segment of memory */ diff --git a/include/minix/syslib.h b/include/minix/syslib.h index 9b5131f55..762a6b181 100644 --- a/include/minix/syslib.h +++ b/include/minix/syslib.h @@ -250,6 +250,8 @@ _PROTOTYPE( char *pci_dev_name, (u16_t vid, u16_t did) ); _PROTOTYPE( char *pci_slot_name, (int devind) ); _PROTOTYPE( int pci_set_acl, (struct rs_pci *rs_pci) ); _PROTOTYPE( int pci_del_acl, (endpoint_t proc_ep) ); +_PROTOTYPE( int pci_get_bar, (int devind, int port, u32_t *base, + u32_t *size, int *ioflag) ); /* Profiling. */ _PROTOTYPE( int sys_sprof, (int action, int size, int freq, diff --git a/lib/libsys/Makefile b/lib/libsys/Makefile index 1a80971b8..ad76629e8 100644 --- a/lib/libsys/Makefile +++ b/lib/libsys/Makefile @@ -17,6 +17,7 @@ SRCS= \ pci_dev_name.c \ pci_find_dev.c \ pci_first_dev.c \ + pci_get_bar.c \ pci_ids.c \ pci_init.c \ pci_init1.c \ diff --git a/lib/libsys/pci_get_bar.c b/lib/libsys/pci_get_bar.c new file mode 100644 index 000000000..6d977f9c7 --- /dev/null +++ b/lib/libsys/pci_get_bar.c @@ -0,0 +1,38 @@ +/* +pci_get_bar.c +*/ + +#include "pci.h" +#include "syslib.h" +#include + +/*===========================================================================* + * pci_get_bar * + *===========================================================================*/ +PUBLIC int pci_get_bar(devind, port, base, size, ioflag) +int devind; +int port; +u32_t *base; +u32_t *size; +int *ioflag; +{ + int r; + message m; + + m.m_type= BUSC_PCI_GET_BAR; + m.BUSC_PGB_DEVIND= devind; + m.BUSC_PGB_PORT= port; + + r= sendrec(pci_procnr, &m); + if (r != 0) + panic("pci_get_bar: can't talk to PCI: %d", r); + + if (m.m_type == 0) + { + *base= m.BUSC_PGB_BASE; + *size= m.BUSC_PGB_SIZE; + *ioflag= m.BUSC_PGB_IOFLAG; + } + return m.m_type; +} +