Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1.  
  2. struct agp_3_5_dev
  3. {
  4.     link_t link;
  5.     int    capndx;
  6.     u32_t  maxbw;
  7.     PCITAG tag;
  8. };
  9.  
  10. static inline list_insert_tail(link_t *new, link_t *old)
  11. {
  12.    new->prev = old;
  13.    new->next = old->next;
  14.    new->next->prev = new;
  15.    old->next = new;
  16. }
  17.  
  18. static void agp_3_5_dev_list_insert(link_t *head, link_t *new)
  19. {
  20.     struct agp_3_5_dev *cur, *n = (struct agp_3_5_dev*)new;
  21.     link_t *pos = head->next;
  22.  
  23.     while(pos != head){
  24.         cur = (struct agp_3_5_dev*)pos;
  25.                 if(cur->maxbw > n->maxbw)
  26.                         break;
  27.         }
  28.     list_insert_tail(new, pos);
  29. }
  30.  
  31. static void agp_3_5_dev_list_sort(link_t *list, unsigned int ndevs)
  32. {
  33.         struct agp_3_5_dev *cur;
  34.     link_t *pos, *tmp, *start = list->next;
  35.     u32_t nistat;
  36.  
  37.     list_initialize(list);
  38.  
  39.     for (pos = start; pos != list; )
  40.     {
  41.         PCITAG tag;
  42.  
  43.         cur = (struct agp_3_5_dev*)pos;
  44.         tag = cur->tag;
  45.  
  46.         nistat = pciReadLong(tag, cur->capndx+AGPNISTAT);
  47.                 cur->maxbw = (nistat >> 16) & 0xff;
  48.  
  49.                 tmp = pos;
  50.                 pos = pos->next;
  51.         agp_3_5_dev_list_insert(list, tmp);
  52.         }
  53. }
  54.  
  55.  
  56. /*
  57.  * Initialize all isochronous transfer parameters for an AGP 3.0
  58.  * node (i.e. a host bridge in combination with the adapters
  59.  * lying behind it...)
  60.  */
  61.  
  62. static int agp_3_5_isochronous_node_enable(agp_t *bridge,
  63.         link_t *dev_list, unsigned int ndevs)
  64. {
  65.         /*
  66.          * Convenience structure to make the calculations clearer
  67.          * here.  The field names come straight from the AGP 3.0 spec.
  68.          */
  69.         struct isoch_data {
  70.         u32_t maxbw;
  71.         u32_t n;
  72.         u32_t y;
  73.         u32_t l;
  74.         u32_t rq;
  75.                 struct agp_3_5_dev *dev;
  76.         };
  77.  
  78.     PCITAG td = bridge->PciTag;
  79.  
  80.   //  struct list_head *head = &dev_list->list, *pos;
  81.         struct agp_3_5_dev *cur;
  82.         struct isoch_data *master, target;
  83.         unsigned int cdev = 0;
  84.     u32_t mnistat, tnistat, tstatus, mcmd;
  85.     u16_t tnicmd, mnicmd;
  86.     u8_t mcapndx;
  87.     u32_t tot_bw = 0, tot_n = 0, tot_rq = 0, y_max, rq_isoch, rq_async;
  88.     u32_t step, rem, rem_isoch, rem_async;
  89.         int ret = 0;
  90.  
  91.         /*
  92.          * We'll work with an array of isoch_data's (one for each
  93.          * device in dev_list) throughout this function.
  94.          */
  95.     if ((master = malloc(ndevs * sizeof(*master))) == NULL) {
  96.         ret = -1;
  97.                 goto get_out;
  98.         }
  99.  
  100.         /*
  101.          * Sort the device list by maxbw.  We need to do this because the
  102.          * spec suggests that the devices with the smallest requirements
  103.          * have their resources allocated first, with all remaining resources
  104.          * falling to the device with the largest requirement.
  105.          *
  106.          * We don't exactly do this, we divide target resources by ndevs
  107.          * and split them amongst the AGP 3.0 devices.  The remainder of such
  108.          * division operations are dropped on the last device, sort of like
  109.          * the spec mentions it should be done.
  110.          *
  111.          * We can't do this sort when we initially construct the dev_list
  112.          * because we don't know until this function whether isochronous
  113.          * transfers are enabled and consequently whether maxbw will mean
  114.          * anything.
  115.          */
  116.    agp_3_5_dev_list_sort(dev_list, ndevs);
  117.  
  118.    tnistat = pciReadLong(td, bridge->capndx+AGPNISTAT);
  119.    tstatus = pciReadLong(td, bridge->capndx+AGPSTAT);
  120.  
  121.         /* Extract power-on defaults from the target */
  122.         target.maxbw = (tnistat >> 16) & 0xff;
  123.         target.n     = (tnistat >> 8)  & 0xff;
  124.         target.y     = (tnistat >> 6)  & 0x3;
  125.         target.l     = (tnistat >> 3)  & 0x7;
  126.         target.rq    = (tstatus >> 24) & 0xff;
  127.  
  128.         y_max = target.y;
  129.  
  130.         /*
  131.          * Extract power-on defaults for each device in dev_list.  Along
  132.          * the way, calculate the total isochronous bandwidth required
  133.          * by these devices and the largest requested payload size.
  134.          */
  135.  
  136.    link_t *pos;
  137.  
  138.    for (pos = dev_list->next; pos != dev_list; pos = pos->next )
  139.    {
  140.        PCITAG dev;
  141.  
  142.        cur = (struct agp_3_5_dev*)pos;
  143.        dev = cur->tag;
  144.  
  145.                 mcapndx = cur->capndx;
  146.  
  147.        mnistat = pciReadLong(dev, cur->capndx+AGPNISTAT);
  148.  
  149.                 master[cdev].maxbw = (mnistat >> 16) & 0xff;
  150.                 master[cdev].n     = (mnistat >> 8)  & 0xff;
  151.                 master[cdev].y     = (mnistat >> 6)  & 0x3;
  152.                 master[cdev].dev   = cur;
  153.  
  154.                 tot_bw += master[cdev].maxbw;
  155.                 y_max = max(y_max, master[cdev].y);
  156.  
  157.                 cdev++;
  158.         }
  159.  
  160.         /* Check if this configuration has any chance of working */
  161.         if (tot_bw > target.maxbw) {
  162.        dbgprintf("isochronous bandwidth required "
  163.                         "by AGP 3.0 devices exceeds that which is supported by "
  164.                         "the AGP 3.0 bridge!\n");
  165.        ret = -1;
  166.                 goto free_and_exit;
  167.         }
  168.  
  169.         target.y = y_max;
  170.  
  171.         /*
  172.          * Write the calculated payload size into the target's NICMD
  173.          * register.  Doing this directly effects the ISOCH_N value
  174.          * in the target's NISTAT register, so we need to do this now
  175.          * to get an accurate value for ISOCH_N later.
  176.          */
  177.    tnicmd = pciReadWord(td, bridge->capndx+AGPNICMD);
  178.         tnicmd &= ~(0x3 << 6);
  179.         tnicmd |= target.y << 6;
  180.    pciWriteWord(td, bridge->capndx+AGPNICMD, tnicmd);
  181.  
  182.         /* Reread the target's ISOCH_N */
  183.     tnistat = pciReadLong(td, bridge->capndx+AGPNISTAT);
  184.         target.n = (tnistat >> 8) & 0xff;
  185.  
  186.         /* Calculate the minimum ISOCH_N needed by each master */
  187.         for (cdev=0; cdev<ndevs; cdev++) {
  188.                 master[cdev].y = target.y;
  189.                 master[cdev].n = master[cdev].maxbw / (master[cdev].y + 1);
  190.  
  191.                 tot_n += master[cdev].n;
  192.         }
  193.  
  194.         /* Exit if the minimal ISOCH_N allocation among the masters is more
  195.          * than the target can handle. */
  196.         if (tot_n > target.n) {
  197.         dbgprintf("number of isochronous "
  198.                         "transactions per period required by AGP 3.0 devices "
  199.                         "exceeds that which is supported by the AGP 3.0 "
  200.                         "bridge!\n");
  201.         ret = -1;
  202.                 goto free_and_exit;
  203.         }
  204.  
  205.         /* Calculate left over ISOCH_N capability in the target.  We'll give
  206.          * this to the hungriest device (as per the spec) */
  207.         rem  = target.n - tot_n;
  208.  
  209.         /*
  210.          * Calculate the minimum isochronous RQ depth needed by each master.
  211.          * Along the way, distribute the extra ISOCH_N capability calculated
  212.          * above.
  213.          */
  214.         for (cdev=0; cdev<ndevs; cdev++) {
  215.                 /*
  216.                  * This is a little subtle.  If ISOCH_Y > 64B, then ISOCH_Y
  217.                  * byte isochronous writes will be broken into 64B pieces.
  218.                  * This means we need to budget more RQ depth to account for
  219.                  * these kind of writes (each isochronous write is actually
  220.                  * many writes on the AGP bus).
  221.                  */
  222.                 master[cdev].rq = master[cdev].n;
  223.                 if(master[cdev].y > 0x1)
  224.                         master[cdev].rq *= (1 << (master[cdev].y - 1));
  225.  
  226.                 tot_rq += master[cdev].rq;
  227.         }
  228.         master[ndevs-1].n += rem;
  229.  
  230.         /* Figure the number of isochronous and asynchronous RQ slots the
  231.          * target is providing. */
  232.         rq_isoch = (target.y > 0x1) ? target.n * (1 << (target.y - 1)) : target.n;
  233.         rq_async = target.rq - rq_isoch;
  234.  
  235.         /* Exit if the minimal RQ needs of the masters exceeds what the target
  236.          * can provide. */
  237.         if (tot_rq > rq_isoch) {
  238.        dbgprintf("number of request queue slots "
  239.                         "required by the isochronous bandwidth requested by "
  240.                         "AGP 3.0 devices exceeds the number provided by the "
  241.                         "AGP 3.0 bridge!\n");
  242.        ret = -1;
  243.                 goto free_and_exit;
  244.         }
  245.  
  246.         /* Calculate asynchronous RQ capability in the target (per master) as
  247.          * well as the total number of leftover isochronous RQ slots. */
  248.         step      = rq_async / ndevs;
  249.         rem_async = step + (rq_async % ndevs);
  250.         rem_isoch = rq_isoch - tot_rq;
  251.  
  252.         /* Distribute the extra RQ slots calculated above and write our
  253.          * isochronous settings out to the actual devices. */
  254.    for (cdev=0; cdev<ndevs; cdev++)
  255.    {
  256.        PCITAG dev;
  257.  
  258.                 cur = master[cdev].dev;
  259.        dev = cur->tag;
  260.  
  261.                 mcapndx = cur->capndx;
  262.  
  263.                 master[cdev].rq += (cdev == ndevs - 1)
  264.                               ? (rem_async + rem_isoch) : step;
  265.  
  266.        mnicmd = pciReadWord(dev, cur->capndx+AGPNICMD);
  267.        mcmd = pciReadLong(dev, cur->capndx+AGPCMD);
  268.  
  269.                 mnicmd &= ~(0xff << 8);
  270.                 mnicmd &= ~(0x3  << 6);
  271.                 mcmd   &= ~(0xff << 24);
  272.  
  273.                 mnicmd |= master[cdev].n  << 8;
  274.                 mnicmd |= master[cdev].y  << 6;
  275.                 mcmd   |= master[cdev].rq << 24;
  276.  
  277.        pciWriteLong(dev, cur->capndx+AGPCMD, mcmd);
  278.        pciWriteWord(dev, cur->capndx+AGPNICMD, mnicmd);
  279.         }
  280.  
  281. free_and_exit:
  282.    free(master);
  283.  
  284. get_out:
  285.         return ret;
  286. }
  287.  
  288.  
  289. /*
  290. * This function basically allocates request queue slots among the
  291. * AGP 3.0 systems in nonisochronous nodes.  The algorithm is
  292. * pretty stupid, divide the total number of RQ slots provided by the
  293. * target by ndevs.  Distribute this many slots to each AGP 3.0 device,
  294. * giving any left over slots to the last device in dev_list.
  295. */
  296. static void agp_3_5_nonisochronous_node_enable(agp_t *bridge,
  297.        link_t *dev_list, unsigned int ndevs)
  298. {
  299.         struct agp_3_5_dev *cur;
  300.    u32_t tstatus, mcmd;
  301.    u32_t trq, mrq, rem;
  302.         unsigned int cdev = 0;
  303.  
  304.    tstatus = pciReadLong(bridge->PciTag, bridge->capndx+AGPSTAT);
  305.  
  306.         trq = (tstatus >> 24) & 0xff;
  307.         mrq = trq / ndevs;
  308.  
  309.         rem = mrq + (trq % ndevs);
  310.  
  311.    link_t *pos;
  312.  
  313.    for (pos = dev_list->next; cdev<ndevs; cdev++, pos=pos->next) {
  314.        cur = (struct agp_3_5_dev*)pos;
  315.  
  316.        mcmd = pciReadLong(cur->tag, cur->capndx+AGPCMD);
  317.                 mcmd &= ~(0xff << 24);
  318.                 mcmd |= ((cdev == ndevs - 1) ? rem : mrq) << 24;
  319.        pciWriteLong(cur->tag, cur->capndx+AGPCMD, mcmd);
  320.         }
  321. }
  322.  
  323.  
  324.  
  325. /*
  326. * Fully configure and enable an AGP 3.0 host bridge and all the devices
  327. * lying behind it.
  328. */
  329. int agp_3_5_enable(agp_t *bridge)
  330. {
  331.    u8_t   mcapndx;
  332.    u32_t  isoch, arqsz;
  333.    u32_t  tstatus, mstatus, ncapid;
  334.    u32_t  mmajor;
  335.    u16_t  mpstat;
  336.  
  337.    link_t dev_list;
  338.  
  339.    struct agp_3_5_dev *cur, *pos;
  340.  
  341.         unsigned int ndevs = 0;
  342.    PCITAG dev = 0;
  343.         int ret = 0;
  344.  
  345.         /* Extract some power-on defaults from the target */
  346.    tstatus = pciReadLong(bridge->PciTag, bridge->capndx+AGPSTAT);
  347.         isoch     = (tstatus >> 17) & 0x1;
  348.         if (isoch == 0) /* isoch xfers not available, bail out. */
  349.        return -1;
  350.  
  351.         arqsz     = (tstatus >> 13) & 0x7;
  352.  
  353.    list_initialize(&dev_list);
  354.  
  355.         /* Find all AGP devices, and add them to dev_list. */
  356.    for_each_pci_dev(dev)
  357.    {
  358.        u16_t devclass;
  359.  
  360.                 mcapndx = pci_find_capability(dev, PCI_CAP_ID_AGP);
  361.                 if (mcapndx == 0)
  362.                         continue;
  363.  
  364.        devclass = pciReadWord(dev, 0x0A);
  365.  
  366.        switch (devclass & 0xff00)
  367.        {
  368.                         case 0x0600:    /* Bridge */
  369.                                 /* Skip bridges. We should call this function for each one. */
  370.                                 continue;
  371.  
  372.                         case 0x0001:    /* Unclassified device */
  373.                                 /* Don't know what this is, but log it for investigation. */
  374.                                 if (mcapndx != 0) {
  375.                     dbgprintf("Wacky, found unclassified AGP device.\n");
  376.                                 }
  377.                                 continue;
  378.  
  379.                         case 0x0300:    /* Display controller */
  380.                         case 0x0400:    /* Multimedia controller */
  381.                 if((cur = malloc(sizeof(*cur))) == NULL)
  382.                 {
  383.                     ret = -1;
  384.                                         goto free_and_exit;
  385.                                 }
  386.                 cur->tag = dev;
  387.                 list_prepend(&cur->link, &dev_list);
  388.                                 ndevs++;
  389.                                 continue;
  390.  
  391.                         default:
  392.                                 continue;
  393.                 }
  394.         }
  395.  
  396.         /*
  397.          * Take an initial pass through the devices lying behind our host
  398.          * bridge.  Make sure each one is actually an AGP 3.0 device, otherwise
  399.          * exit with an error message.  Along the way store the AGP 3.0
  400.          * cap_ptr for each device
  401.          */
  402.  
  403.     cur = (struct agp_3_5_dev*)dev_list.next;
  404.  
  405.     while(&cur->link != &dev_list)
  406.     {
  407.         dev = cur->tag;
  408.  
  409.         mpstat = pciReadWord(dev, PCI_STATUS);
  410.                 if ((mpstat & PCI_STATUS_CAP_LIST) == 0)
  411.                         continue;
  412.  
  413.         mcapndx = pciReadByte(dev, PCI_CAPABILITY_LIST);
  414.                 if (mcapndx != 0) {
  415.                         do {
  416.                 ncapid = pciReadLong(dev, mcapndx);
  417.                                 if ((ncapid & 0xff) != 2)
  418.                                         mcapndx = (ncapid >> 8) & 0xff;
  419.                         }
  420.                         while (((ncapid & 0xff) != 2) && (mcapndx != 0));
  421.                 }
  422.  
  423.                 if (mcapndx == 0) {
  424.             dbgprintf("woah!  Non-AGP device "
  425.                                 "found on the secondary bus of an AGP 3.5 bridge!\n");
  426.             ret = -1;
  427.                         goto free_and_exit;
  428.                 }
  429.  
  430.                 mmajor = (ncapid >> AGP_MAJOR_VERSION_SHIFT) & 0xf;
  431.                 if (mmajor < 3) {
  432.             dbgprintf("woah!  AGP 2.0 device "
  433.                                 "found on the secondary bus of an AGP 3.5 "
  434.                                 "bridge operating with AGP 3.0 electricals!\n");
  435.             ret = -1;
  436.                         goto free_and_exit;
  437.                 }
  438.  
  439.                 cur->capndx = mcapndx;
  440.  
  441.         mstatus = pciReadLong(dev, cur->capndx+AGPSTAT);
  442.  
  443.                 if (((mstatus >> 3) & 0x1) == 0) {
  444.             dbgprintf("woah!  AGP 3.x device "
  445.                                 "not operating in AGP 3.x mode found on the "
  446.                                 "secondary bus of an AGP 3.5 bridge operating "
  447.                                 "with AGP 3.0 electricals!\n");
  448.             ret = -1;
  449.                         goto free_and_exit;
  450.                 }
  451.         cur = (struct agp_3_5_dev*)cur->link.next;
  452.         }
  453.  
  454.         /*
  455.          * Call functions to divide target resources amongst the AGP 3.0
  456.          * masters.  This process is dramatically different depending on
  457.          * whether isochronous transfers are supported.
  458.          */
  459.         if (isoch) {
  460.         ret = agp_3_5_isochronous_node_enable(bridge, &dev_list, ndevs);
  461.                 if (ret) {
  462.             dbgprintf("Something bad happened setting "
  463.                       "up isochronous xfers.  Falling back to "
  464.                       "non-isochronous xfer mode.\n");
  465.                 } else {
  466.                         goto free_and_exit;
  467.                 }
  468.         }
  469.     agp_3_5_nonisochronous_node_enable(bridge, &dev_list, ndevs);
  470.  
  471. free_and_exit:
  472.         /* Be sure to free the dev_list */
  473.     for (pos = (struct agp_3_5_dev*)dev_list.next; &pos->link != &dev_list; )
  474.     {
  475.         cur = pos;
  476.  
  477.         pos = (struct agp_3_5_dev*)pos->link.next;
  478.         free(cur);
  479.         }
  480.  
  481. get_out:
  482.         return ret;
  483. }
  484.