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 */
/* Initialize the device.
*/
u32_t bar;
- int r;
+ int r, flag;
/* Initialize global state. */
state.devind = 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");
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. */
/* 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 */
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) );
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);
}
}
+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;
{
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 *
*===========================================================================*/
_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) );
#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
*/
_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,
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 \
--- /dev/null
+/*
+pci_get_bar.c
+*/
+
+#include "pci.h"
+#include "syslib.h"
+#include <minix/sysutil.h>
+
+/*===========================================================================*
+ * 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;
+}
+