Path: blob/master/arch/cris/arch-v32/mach-fs/arbiter.c
15125 views
/*1* Memory arbiter functions. Allocates bandwidth through the2* arbiter and sets up arbiter breakpoints.3*4* The algorithm first assigns slots to the clients that has specified5* bandwidth (e.g. ethernet) and then the remaining slots are divided6* on all the active clients.7*8* Copyright (c) 2004-2007 Axis Communications AB.9*/1011#include <hwregs/reg_map.h>12#include <hwregs/reg_rdwr.h>13#include <hwregs/marb_defs.h>14#include <arbiter.h>15#include <hwregs/intr_vect.h>16#include <linux/interrupt.h>17#include <linux/signal.h>18#include <linux/errno.h>19#include <linux/spinlock.h>20#include <asm/io.h>21#include <asm/irq_regs.h>2223struct crisv32_watch_entry {24unsigned long instance;25watch_callback *cb;26unsigned long start;27unsigned long end;28int used;29};3031#define NUMBER_OF_BP 432#define NBR_OF_CLIENTS 1433#define NBR_OF_SLOTS 6434#define SDRAM_BANDWIDTH 100000000 /* Some kind of expected value */35#define INTMEM_BANDWIDTH 40000000036#define NBR_OF_REGIONS 23738static struct crisv32_watch_entry watches[NUMBER_OF_BP] = {39{regi_marb_bp0},40{regi_marb_bp1},41{regi_marb_bp2},42{regi_marb_bp3}43};4445static u8 requested_slots[NBR_OF_REGIONS][NBR_OF_CLIENTS];46static u8 active_clients[NBR_OF_REGIONS][NBR_OF_CLIENTS];47static int max_bandwidth[NBR_OF_REGIONS] =48{ SDRAM_BANDWIDTH, INTMEM_BANDWIDTH };4950DEFINE_SPINLOCK(arbiter_lock);5152static irqreturn_t crisv32_arbiter_irq(int irq, void *dev_id);5354/*55* "I'm the arbiter, I know the score.56* From square one I'll be watching all 64."57* (memory arbiter slots, that is)58*59* Or in other words:60* Program the memory arbiter slots for "region" according to what's61* in requested_slots[] and active_clients[], while minimizing62* latency. A caller may pass a non-zero positive amount for63* "unused_slots", which must then be the unallocated, remaining64* number of slots, free to hand out to any client.65*/6667static void crisv32_arbiter_config(int region, int unused_slots)68{69int slot;70int client;71int interval = 0;7273/*74* This vector corresponds to the hardware arbiter slots (see75* the hardware documentation for semantics). We initialize76* each slot with a suitable sentinel value outside the valid77* range {0 .. NBR_OF_CLIENTS - 1} and replace them with78* client indexes. Then it's fed to the hardware.79*/80s8 val[NBR_OF_SLOTS];8182for (slot = 0; slot < NBR_OF_SLOTS; slot++)83val[slot] = -1;8485for (client = 0; client < NBR_OF_CLIENTS; client++) {86int pos;87/* Allocate the requested non-zero number of slots, but88* also give clients with zero-requests one slot each89* while stocks last. We do the latter here, in client90* order. This makes sure zero-request clients are the91* first to get to any spare slots, else those slots92* could, when bandwidth is allocated close to the limit,93* all be allocated to low-index non-zero-request clients94* in the default-fill loop below. Another positive but95* secondary effect is a somewhat better spread of the96* zero-bandwidth clients in the vector, avoiding some of97* the latency that could otherwise be caused by the98* partitioning of non-zero-bandwidth clients at low99* indexes and zero-bandwidth clients at high100* indexes. (Note that this spreading can only affect the101* unallocated bandwidth.) All the above only matters for102* memory-intensive situations, of course.103*/104if (!requested_slots[region][client]) {105/*106* Skip inactive clients. Also skip zero-slot107* allocations in this pass when there are no known108* free slots.109*/110if (!active_clients[region][client]111|| unused_slots <= 0)112continue;113114unused_slots--;115116/* Only allocate one slot for this client. */117interval = NBR_OF_SLOTS;118} else119interval =120NBR_OF_SLOTS / requested_slots[region][client];121122pos = 0;123while (pos < NBR_OF_SLOTS) {124if (val[pos] >= 0)125pos++;126else {127val[pos] = client;128pos += interval;129}130}131}132133client = 0;134for (slot = 0; slot < NBR_OF_SLOTS; slot++) {135/*136* Allocate remaining slots in round-robin137* client-number order for active clients. For this138* pass, we ignore requested bandwidth and previous139* allocations.140*/141if (val[slot] < 0) {142int first = client;143while (!active_clients[region][client]) {144client = (client + 1) % NBR_OF_CLIENTS;145if (client == first)146break;147}148val[slot] = client;149client = (client + 1) % NBR_OF_CLIENTS;150}151if (region == EXT_REGION)152REG_WR_INT_VECT(marb, regi_marb, rw_ext_slots, slot,153val[slot]);154else if (region == INT_REGION)155REG_WR_INT_VECT(marb, regi_marb, rw_int_slots, slot,156val[slot]);157}158}159160extern char _stext, _etext;161162static void crisv32_arbiter_init(void)163{164static int initialized;165166if (initialized)167return;168169initialized = 1;170171/*172* CPU caches are always set to active, but with zero173* bandwidth allocated. It should be ok to allocate zero174* bandwidth for the caches, because DMA for other channels175* will supposedly finish, once their programmed amount is176* done, and then the caches will get access according to the177* "fixed scheme" for unclaimed slots. Though, if for some178* use-case somewhere, there's a maximum CPU latency for179* e.g. some interrupt, we have to start allocating specific180* bandwidth for the CPU caches too.181*/182active_clients[EXT_REGION][10] = active_clients[EXT_REGION][11] = 1;183crisv32_arbiter_config(EXT_REGION, 0);184crisv32_arbiter_config(INT_REGION, 0);185186if (request_irq(MEMARB_INTR_VECT, crisv32_arbiter_irq, IRQF_DISABLED,187"arbiter", NULL))188printk(KERN_ERR "Couldn't allocate arbiter IRQ\n");189190#ifndef CONFIG_ETRAX_KGDB191/* Global watch for writes to kernel text segment. */192crisv32_arbiter_watch(virt_to_phys(&_stext), &_etext - &_stext,193arbiter_all_clients, arbiter_all_write, NULL);194#endif195}196197/* Main entry for bandwidth allocation. */198199int crisv32_arbiter_allocate_bandwidth(int client, int region,200unsigned long bandwidth)201{202int i;203int total_assigned = 0;204int total_clients = 0;205int req;206207crisv32_arbiter_init();208209for (i = 0; i < NBR_OF_CLIENTS; i++) {210total_assigned += requested_slots[region][i];211total_clients += active_clients[region][i];212}213214/* Avoid division by 0 for 0-bandwidth requests. */215req = bandwidth == 0216? 0 : NBR_OF_SLOTS / (max_bandwidth[region] / bandwidth);217218/*219* We make sure that there are enough slots only for non-zero220* requests. Requesting 0 bandwidth *may* allocate slots,221* though if all bandwidth is allocated, such a client won't222* get any and will have to rely on getting memory access223* according to the fixed scheme that's the default when one224* of the slot-allocated clients doesn't claim their slot.225*/226if (total_assigned + req > NBR_OF_SLOTS)227return -ENOMEM;228229active_clients[region][client] = 1;230requested_slots[region][client] = req;231crisv32_arbiter_config(region, NBR_OF_SLOTS - total_assigned);232233return 0;234}235236/*237* Main entry for bandwidth deallocation.238*239* Strictly speaking, for a somewhat constant set of clients where240* each client gets a constant bandwidth and is just enabled or241* disabled (somewhat dynamically), no action is necessary here to242* avoid starvation for non-zero-allocation clients, as the allocated243* slots will just be unused. However, handing out those unused slots244* to active clients avoids needless latency if the "fixed scheme"245* would give unclaimed slots to an eager low-index client.246*/247248void crisv32_arbiter_deallocate_bandwidth(int client, int region)249{250int i;251int total_assigned = 0;252253requested_slots[region][client] = 0;254active_clients[region][client] = 0;255256for (i = 0; i < NBR_OF_CLIENTS; i++)257total_assigned += requested_slots[region][i];258259crisv32_arbiter_config(region, NBR_OF_SLOTS - total_assigned);260}261262int crisv32_arbiter_watch(unsigned long start, unsigned long size,263unsigned long clients, unsigned long accesses,264watch_callback *cb)265{266int i;267268crisv32_arbiter_init();269270if (start > 0x80000000) {271printk(KERN_ERR "Arbiter: %lX doesn't look like a "272"physical address", start);273return -EFAULT;274}275276spin_lock(&arbiter_lock);277278for (i = 0; i < NUMBER_OF_BP; i++) {279if (!watches[i].used) {280reg_marb_rw_intr_mask intr_mask =281REG_RD(marb, regi_marb, rw_intr_mask);282283watches[i].used = 1;284watches[i].start = start;285watches[i].end = start + size;286watches[i].cb = cb;287288REG_WR_INT(marb_bp, watches[i].instance, rw_first_addr,289watches[i].start);290REG_WR_INT(marb_bp, watches[i].instance, rw_last_addr,291watches[i].end);292REG_WR_INT(marb_bp, watches[i].instance, rw_op,293accesses);294REG_WR_INT(marb_bp, watches[i].instance, rw_clients,295clients);296297if (i == 0)298intr_mask.bp0 = regk_marb_yes;299else if (i == 1)300intr_mask.bp1 = regk_marb_yes;301else if (i == 2)302intr_mask.bp2 = regk_marb_yes;303else if (i == 3)304intr_mask.bp3 = regk_marb_yes;305306REG_WR(marb, regi_marb, rw_intr_mask, intr_mask);307spin_unlock(&arbiter_lock);308309return i;310}311}312spin_unlock(&arbiter_lock);313return -ENOMEM;314}315316int crisv32_arbiter_unwatch(int id)317{318reg_marb_rw_intr_mask intr_mask = REG_RD(marb, regi_marb, rw_intr_mask);319320crisv32_arbiter_init();321322spin_lock(&arbiter_lock);323324if ((id < 0) || (id >= NUMBER_OF_BP) || (!watches[id].used)) {325spin_unlock(&arbiter_lock);326return -EINVAL;327}328329memset(&watches[id], 0, sizeof(struct crisv32_watch_entry));330331if (id == 0)332intr_mask.bp0 = regk_marb_no;333else if (id == 1)334intr_mask.bp1 = regk_marb_no;335else if (id == 2)336intr_mask.bp2 = regk_marb_no;337else if (id == 3)338intr_mask.bp3 = regk_marb_no;339340REG_WR(marb, regi_marb, rw_intr_mask, intr_mask);341342spin_unlock(&arbiter_lock);343return 0;344}345346extern void show_registers(struct pt_regs *regs);347348static irqreturn_t crisv32_arbiter_irq(int irq, void *dev_id)349{350reg_marb_r_masked_intr masked_intr =351REG_RD(marb, regi_marb, r_masked_intr);352reg_marb_bp_r_brk_clients r_clients;353reg_marb_bp_r_brk_addr r_addr;354reg_marb_bp_r_brk_op r_op;355reg_marb_bp_r_brk_first_client r_first;356reg_marb_bp_r_brk_size r_size;357reg_marb_bp_rw_ack ack = { 0 };358reg_marb_rw_ack_intr ack_intr = {359.bp0 = 1, .bp1 = 1, .bp2 = 1, .bp3 = 1360};361struct crisv32_watch_entry *watch;362363if (masked_intr.bp0) {364watch = &watches[0];365ack_intr.bp0 = regk_marb_yes;366} else if (masked_intr.bp1) {367watch = &watches[1];368ack_intr.bp1 = regk_marb_yes;369} else if (masked_intr.bp2) {370watch = &watches[2];371ack_intr.bp2 = regk_marb_yes;372} else if (masked_intr.bp3) {373watch = &watches[3];374ack_intr.bp3 = regk_marb_yes;375} else {376return IRQ_NONE;377}378379/* Retrieve all useful information and print it. */380r_clients = REG_RD(marb_bp, watch->instance, r_brk_clients);381r_addr = REG_RD(marb_bp, watch->instance, r_brk_addr);382r_op = REG_RD(marb_bp, watch->instance, r_brk_op);383r_first = REG_RD(marb_bp, watch->instance, r_brk_first_client);384r_size = REG_RD(marb_bp, watch->instance, r_brk_size);385386printk(KERN_INFO "Arbiter IRQ\n");387printk(KERN_INFO "Clients %X addr %X op %X first %X size %X\n",388REG_TYPE_CONV(int, reg_marb_bp_r_brk_clients, r_clients),389REG_TYPE_CONV(int, reg_marb_bp_r_brk_addr, r_addr),390REG_TYPE_CONV(int, reg_marb_bp_r_brk_op, r_op),391REG_TYPE_CONV(int, reg_marb_bp_r_brk_first_client, r_first),392REG_TYPE_CONV(int, reg_marb_bp_r_brk_size, r_size));393394REG_WR(marb_bp, watch->instance, rw_ack, ack);395REG_WR(marb, regi_marb, rw_ack_intr, ack_intr);396397printk(KERN_INFO "IRQ occurred at %lX\n", get_irq_regs()->erp);398399if (watch->cb)400watch->cb();401402return IRQ_HANDLED;403}404405406