linux/arch/cris/arch-v32/mach-fs/arbiter.c
<<
>>
Prefs
   1/*
   2 * Memory arbiter functions. Allocates bandwidth through the
   3 * arbiter and sets up arbiter breakpoints.
   4 *
   5 * The algorithm first assigns slots to the clients that has specified
   6 * bandwidth (e.g. ethernet) and then the remaining slots are divided
   7 * on all the active clients.
   8 *
   9 * Copyright (c) 2004-2007 Axis Communications AB.
  10 */
  11
  12#include <hwregs/reg_map.h>
  13#include <hwregs/reg_rdwr.h>
  14#include <hwregs/marb_defs.h>
  15#include <arbiter.h>
  16#include <hwregs/intr_vect.h>
  17#include <linux/interrupt.h>
  18#include <linux/signal.h>
  19#include <linux/errno.h>
  20#include <linux/spinlock.h>
  21#include <asm/io.h>
  22#include <asm/irq_regs.h>
  23
  24struct crisv32_watch_entry {
  25        unsigned long instance;
  26        watch_callback *cb;
  27        unsigned long start;
  28        unsigned long end;
  29        int used;
  30};
  31
  32#define NUMBER_OF_BP 4
  33#define NBR_OF_CLIENTS 14
  34#define NBR_OF_SLOTS 64
  35#define SDRAM_BANDWIDTH 100000000       /* Some kind of expected value */
  36#define INTMEM_BANDWIDTH 400000000
  37#define NBR_OF_REGIONS 2
  38
  39static struct crisv32_watch_entry watches[NUMBER_OF_BP] = {
  40        {regi_marb_bp0},
  41        {regi_marb_bp1},
  42        {regi_marb_bp2},
  43        {regi_marb_bp3}
  44};
  45
  46static u8 requested_slots[NBR_OF_REGIONS][NBR_OF_CLIENTS];
  47static u8 active_clients[NBR_OF_REGIONS][NBR_OF_CLIENTS];
  48static int max_bandwidth[NBR_OF_REGIONS] =
  49    { SDRAM_BANDWIDTH, INTMEM_BANDWIDTH };
  50
  51DEFINE_SPINLOCK(arbiter_lock);
  52
  53static irqreturn_t crisv32_arbiter_irq(int irq, void *dev_id);
  54
  55/*
  56 * "I'm the arbiter, I know the score.
  57 *  From square one I'll be watching all 64."
  58 * (memory arbiter slots, that is)
  59 *
  60 *  Or in other words:
  61 * Program the memory arbiter slots for "region" according to what's
  62 * in requested_slots[] and active_clients[], while minimizing
  63 * latency. A caller may pass a non-zero positive amount for
  64 * "unused_slots", which must then be the unallocated, remaining
  65 * number of slots, free to hand out to any client.
  66 */
  67
  68static void crisv32_arbiter_config(int region, int unused_slots)
  69{
  70        int slot;
  71        int client;
  72        int interval = 0;
  73
  74        /*
  75         * This vector corresponds to the hardware arbiter slots (see
  76         * the hardware documentation for semantics). We initialize
  77         * each slot with a suitable sentinel value outside the valid
  78         * range {0 .. NBR_OF_CLIENTS - 1} and replace them with
  79         * client indexes. Then it's fed to the hardware.
  80         */
  81        s8 val[NBR_OF_SLOTS];
  82
  83        for (slot = 0; slot < NBR_OF_SLOTS; slot++)
  84                val[slot] = -1;
  85
  86        for (client = 0; client < NBR_OF_CLIENTS; client++) {
  87                int pos;
  88                /* Allocate the requested non-zero number of slots, but
  89                 * also give clients with zero-requests one slot each
  90                 * while stocks last. We do the latter here, in client
  91                 * order. This makes sure zero-request clients are the
  92                 * first to get to any spare slots, else those slots
  93                 * could, when bandwidth is allocated close to the limit,
  94                 * all be allocated to low-index non-zero-request clients
  95                 * in the default-fill loop below. Another positive but
  96                 * secondary effect is a somewhat better spread of the
  97                 * zero-bandwidth clients in the vector, avoiding some of
  98                 * the latency that could otherwise be caused by the
  99                 * partitioning of non-zero-bandwidth clients at low
 100                 * indexes and zero-bandwidth clients at high
 101                 * indexes. (Note that this spreading can only affect the
 102                 * unallocated bandwidth.)  All the above only matters for
 103                 * memory-intensive situations, of course.
 104                 */
 105                if (!requested_slots[region][client]) {
 106                        /*
 107                         * Skip inactive clients. Also skip zero-slot
 108                         * allocations in this pass when there are no known
 109                         * free slots.
 110                         */
 111                        if (!active_clients[region][client]
 112                            || unused_slots <= 0)
 113                                continue;
 114
 115                        unused_slots--;
 116
 117                        /* Only allocate one slot for this client. */
 118                        interval = NBR_OF_SLOTS;
 119                } else
 120                        interval =
 121                            NBR_OF_SLOTS / requested_slots[region][client];
 122
 123                pos = 0;
 124                while (pos < NBR_OF_SLOTS) {
 125                        if (val[pos] >= 0)
 126                                pos++;
 127                        else {
 128                                val[pos] = client;
 129                                pos += interval;
 130                        }
 131                }
 132        }
 133
 134        client = 0;
 135        for (slot = 0; slot < NBR_OF_SLOTS; slot++) {
 136                /*
 137                 * Allocate remaining slots in round-robin
 138                 * client-number order for active clients. For this
 139                 * pass, we ignore requested bandwidth and previous
 140                 * allocations.
 141                 */
 142                if (val[slot] < 0) {
 143                        int first = client;
 144                        while (!active_clients[region][client]) {
 145                                client = (client + 1) % NBR_OF_CLIENTS;
 146                                if (client == first)
 147                                        break;
 148                        }
 149                        val[slot] = client;
 150                        client = (client + 1) % NBR_OF_CLIENTS;
 151                }
 152                if (region == EXT_REGION)
 153                        REG_WR_INT_VECT(marb, regi_marb, rw_ext_slots, slot,
 154                                        val[slot]);
 155                else if (region == INT_REGION)
 156                        REG_WR_INT_VECT(marb, regi_marb, rw_int_slots, slot,
 157                                        val[slot]);
 158        }
 159}
 160
 161extern char _stext, _etext;
 162
 163static void crisv32_arbiter_init(void)
 164{
 165        static int initialized;
 166
 167        if (initialized)
 168                return;
 169
 170        initialized = 1;
 171
 172        /*
 173         * CPU caches are always set to active, but with zero
 174         * bandwidth allocated. It should be ok to allocate zero
 175         * bandwidth for the caches, because DMA for other channels
 176         * will supposedly finish, once their programmed amount is
 177         * done, and then the caches will get access according to the
 178         * "fixed scheme" for unclaimed slots. Though, if for some
 179         * use-case somewhere, there's a maximum CPU latency for
 180         * e.g. some interrupt, we have to start allocating specific
 181         * bandwidth for the CPU caches too.
 182         */
 183        active_clients[EXT_REGION][10] = active_clients[EXT_REGION][11] = 1;
 184        crisv32_arbiter_config(EXT_REGION, 0);
 185        crisv32_arbiter_config(INT_REGION, 0);
 186
 187        if (request_irq(MEMARB_INTR_VECT, crisv32_arbiter_irq, IRQF_DISABLED,
 188                        "arbiter", NULL))
 189                printk(KERN_ERR "Couldn't allocate arbiter IRQ\n");
 190
 191#ifndef CONFIG_ETRAX_KGDB
 192        /* Global watch for writes to kernel text segment. */
 193        crisv32_arbiter_watch(virt_to_phys(&_stext), &_etext - &_stext,
 194                              arbiter_all_clients, arbiter_all_write, NULL);
 195#endif
 196}
 197
 198/* Main entry for bandwidth allocation. */
 199
 200int crisv32_arbiter_allocate_bandwidth(int client, int region,
 201                                       unsigned long bandwidth)
 202{
 203        int i;
 204        int total_assigned = 0;
 205        int total_clients = 0;
 206        int req;
 207
 208        crisv32_arbiter_init();
 209
 210        for (i = 0; i < NBR_OF_CLIENTS; i++) {
 211                total_assigned += requested_slots[region][i];
 212                total_clients += active_clients[region][i];
 213        }
 214
 215        /* Avoid division by 0 for 0-bandwidth requests. */
 216        req = bandwidth == 0
 217            ? 0 : NBR_OF_SLOTS / (max_bandwidth[region] / bandwidth);
 218
 219        /*
 220         * We make sure that there are enough slots only for non-zero
 221         * requests. Requesting 0 bandwidth *may* allocate slots,
 222         * though if all bandwidth is allocated, such a client won't
 223         * get any and will have to rely on getting memory access
 224         * according to the fixed scheme that's the default when one
 225         * of the slot-allocated clients doesn't claim their slot.
 226         */
 227        if (total_assigned + req > NBR_OF_SLOTS)
 228                return -ENOMEM;
 229
 230        active_clients[region][client] = 1;
 231        requested_slots[region][client] = req;
 232        crisv32_arbiter_config(region, NBR_OF_SLOTS - total_assigned);
 233
 234        return 0;
 235}
 236
 237/*
 238 * Main entry for bandwidth deallocation.
 239 *
 240 * Strictly speaking, for a somewhat constant set of clients where
 241 * each client gets a constant bandwidth and is just enabled or
 242 * disabled (somewhat dynamically), no action is necessary here to
 243 * avoid starvation for non-zero-allocation clients, as the allocated
 244 * slots will just be unused. However, handing out those unused slots
 245 * to active clients avoids needless latency if the "fixed scheme"
 246 * would give unclaimed slots to an eager low-index client.
 247 */
 248
 249void crisv32_arbiter_deallocate_bandwidth(int client, int region)
 250{
 251        int i;
 252        int total_assigned = 0;
 253
 254        requested_slots[region][client] = 0;
 255        active_clients[region][client] = 0;
 256
 257        for (i = 0; i < NBR_OF_CLIENTS; i++)
 258                total_assigned += requested_slots[region][i];
 259
 260        crisv32_arbiter_config(region, NBR_OF_SLOTS - total_assigned);
 261}
 262
 263int crisv32_arbiter_watch(unsigned long start, unsigned long size,
 264                          unsigned long clients, unsigned long accesses,
 265                          watch_callback *cb)
 266{
 267        int i;
 268
 269        crisv32_arbiter_init();
 270
 271        if (start > 0x80000000) {
 272                printk(KERN_ERR "Arbiter: %lX doesn't look like a "
 273                        "physical address", start);
 274                return -EFAULT;
 275        }
 276
 277        spin_lock(&arbiter_lock);
 278
 279        for (i = 0; i < NUMBER_OF_BP; i++) {
 280                if (!watches[i].used) {
 281                        reg_marb_rw_intr_mask intr_mask =
 282                            REG_RD(marb, regi_marb, rw_intr_mask);
 283
 284                        watches[i].used = 1;
 285                        watches[i].start = start;
 286                        watches[i].end = start + size;
 287                        watches[i].cb = cb;
 288
 289                        REG_WR_INT(marb_bp, watches[i].instance, rw_first_addr,
 290                                   watches[i].start);
 291                        REG_WR_INT(marb_bp, watches[i].instance, rw_last_addr,
 292                                   watches[i].end);
 293                        REG_WR_INT(marb_bp, watches[i].instance, rw_op,
 294                                   accesses);
 295                        REG_WR_INT(marb_bp, watches[i].instance, rw_clients,
 296                                   clients);
 297
 298                        if (i == 0)
 299                                intr_mask.bp0 = regk_marb_yes;
 300                        else if (i == 1)
 301                                intr_mask.bp1 = regk_marb_yes;
 302                        else if (i == 2)
 303                                intr_mask.bp2 = regk_marb_yes;
 304                        else if (i == 3)
 305                                intr_mask.bp3 = regk_marb_yes;
 306
 307                        REG_WR(marb, regi_marb, rw_intr_mask, intr_mask);
 308                        spin_unlock(&arbiter_lock);
 309
 310                        return i;
 311                }
 312        }
 313        spin_unlock(&arbiter_lock);
 314        return -ENOMEM;
 315}
 316
 317int crisv32_arbiter_unwatch(int id)
 318{
 319        reg_marb_rw_intr_mask intr_mask = REG_RD(marb, regi_marb, rw_intr_mask);
 320
 321        crisv32_arbiter_init();
 322
 323        spin_lock(&arbiter_lock);
 324
 325        if ((id < 0) || (id >= NUMBER_OF_BP) || (!watches[id].used)) {
 326                spin_unlock(&arbiter_lock);
 327                return -EINVAL;
 328        }
 329
 330        memset(&watches[id], 0, sizeof(struct crisv32_watch_entry));
 331
 332        if (id == 0)
 333                intr_mask.bp0 = regk_marb_no;
 334        else if (id == 1)
 335                intr_mask.bp1 = regk_marb_no;
 336        else if (id == 2)
 337                intr_mask.bp2 = regk_marb_no;
 338        else if (id == 3)
 339                intr_mask.bp3 = regk_marb_no;
 340
 341        REG_WR(marb, regi_marb, rw_intr_mask, intr_mask);
 342
 343        spin_unlock(&arbiter_lock);
 344        return 0;
 345}
 346
 347extern void show_registers(struct pt_regs *regs);
 348
 349static irqreturn_t crisv32_arbiter_irq(int irq, void *dev_id)
 350{
 351        reg_marb_r_masked_intr masked_intr =
 352            REG_RD(marb, regi_marb, r_masked_intr);
 353        reg_marb_bp_r_brk_clients r_clients;
 354        reg_marb_bp_r_brk_addr r_addr;
 355        reg_marb_bp_r_brk_op r_op;
 356        reg_marb_bp_r_brk_first_client r_first;
 357        reg_marb_bp_r_brk_size r_size;
 358        reg_marb_bp_rw_ack ack = { 0 };
 359        reg_marb_rw_ack_intr ack_intr = {
 360                .bp0 = 1, .bp1 = 1, .bp2 = 1, .bp3 = 1
 361        };
 362        struct crisv32_watch_entry *watch;
 363
 364        if (masked_intr.bp0) {
 365                watch = &watches[0];
 366                ack_intr.bp0 = regk_marb_yes;
 367        } else if (masked_intr.bp1) {
 368                watch = &watches[1];
 369                ack_intr.bp1 = regk_marb_yes;
 370        } else if (masked_intr.bp2) {
 371                watch = &watches[2];
 372                ack_intr.bp2 = regk_marb_yes;
 373        } else if (masked_intr.bp3) {
 374                watch = &watches[3];
 375                ack_intr.bp3 = regk_marb_yes;
 376        } else {
 377                return IRQ_NONE;
 378        }
 379
 380        /* Retrieve all useful information and print it. */
 381        r_clients = REG_RD(marb_bp, watch->instance, r_brk_clients);
 382        r_addr = REG_RD(marb_bp, watch->instance, r_brk_addr);
 383        r_op = REG_RD(marb_bp, watch->instance, r_brk_op);
 384        r_first = REG_RD(marb_bp, watch->instance, r_brk_first_client);
 385        r_size = REG_RD(marb_bp, watch->instance, r_brk_size);
 386
 387        printk(KERN_INFO "Arbiter IRQ\n");
 388        printk(KERN_INFO "Clients %X addr %X op %X first %X size %X\n",
 389               REG_TYPE_CONV(int, reg_marb_bp_r_brk_clients, r_clients),
 390               REG_TYPE_CONV(int, reg_marb_bp_r_brk_addr, r_addr),
 391               REG_TYPE_CONV(int, reg_marb_bp_r_brk_op, r_op),
 392               REG_TYPE_CONV(int, reg_marb_bp_r_brk_first_client, r_first),
 393               REG_TYPE_CONV(int, reg_marb_bp_r_brk_size, r_size));
 394
 395        REG_WR(marb_bp, watch->instance, rw_ack, ack);
 396        REG_WR(marb, regi_marb, rw_ack_intr, ack_intr);
 397
 398        printk(KERN_INFO "IRQ occurred at %lX\n", get_irq_regs()->erp);
 399
 400        if (watch->cb)
 401                watch->cb();
 402
 403        return IRQ_HANDLED;
 404}
 405